162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the internal tuner of Montage M88RS6000 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "m88rs6000t.h" 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct m88rs6000t_dev { 1262306a36Sopenharmony_ci struct m88rs6000t_config cfg; 1362306a36Sopenharmony_ci struct i2c_client *client; 1462306a36Sopenharmony_ci struct regmap *regmap; 1562306a36Sopenharmony_ci u32 frequency_khz; 1662306a36Sopenharmony_ci}; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct m88rs6000t_reg_val { 1962306a36Sopenharmony_ci u8 reg; 2062306a36Sopenharmony_ci u8 val; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* set demod main mclk and ts mclk */ 2462306a36Sopenharmony_cistatic int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 2762306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 2862306a36Sopenharmony_ci u8 reg11, reg15, reg16, reg1D, reg1E, reg1F; 2962306a36Sopenharmony_ci u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0; 3062306a36Sopenharmony_ci u16 pll_div_fb; 3162306a36Sopenharmony_ci u32 div, ts_mclk; 3262306a36Sopenharmony_ci unsigned int utmp; 3362306a36Sopenharmony_ci int ret; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* select demod main mclk */ 3662306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x15, &utmp); 3762306a36Sopenharmony_ci if (ret) 3862306a36Sopenharmony_ci goto err; 3962306a36Sopenharmony_ci reg15 = utmp; 4062306a36Sopenharmony_ci if (c->symbol_rate > 45010000) { 4162306a36Sopenharmony_ci reg11 = 0x0E; 4262306a36Sopenharmony_ci reg15 |= 0x02; 4362306a36Sopenharmony_ci reg16 = 115; /* mclk = 110.25MHz */ 4462306a36Sopenharmony_ci } else { 4562306a36Sopenharmony_ci reg11 = 0x0A; 4662306a36Sopenharmony_ci reg15 &= ~0x02; 4762306a36Sopenharmony_ci reg16 = 96; /* mclk = 96MHz */ 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* set ts mclk */ 5162306a36Sopenharmony_ci if (c->delivery_system == SYS_DVBS) 5262306a36Sopenharmony_ci ts_mclk = 96000; 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci ts_mclk = 144000; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci pll_div_fb = (reg15 & 0x01) << 8; 5762306a36Sopenharmony_ci pll_div_fb += reg16; 5862306a36Sopenharmony_ci pll_div_fb += 32; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci div = 36000 * pll_div_fb; 6162306a36Sopenharmony_ci div /= ts_mclk; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (div <= 32) { 6462306a36Sopenharmony_ci N = 2; 6562306a36Sopenharmony_ci f0 = 0; 6662306a36Sopenharmony_ci f1 = div / 2; 6762306a36Sopenharmony_ci f2 = div - f1; 6862306a36Sopenharmony_ci f3 = 0; 6962306a36Sopenharmony_ci } else if (div <= 48) { 7062306a36Sopenharmony_ci N = 3; 7162306a36Sopenharmony_ci f0 = div / 3; 7262306a36Sopenharmony_ci f1 = (div - f0) / 2; 7362306a36Sopenharmony_ci f2 = div - f0 - f1; 7462306a36Sopenharmony_ci f3 = 0; 7562306a36Sopenharmony_ci } else if (div <= 64) { 7662306a36Sopenharmony_ci N = 4; 7762306a36Sopenharmony_ci f0 = div / 4; 7862306a36Sopenharmony_ci f1 = (div - f0) / 3; 7962306a36Sopenharmony_ci f2 = (div - f0 - f1) / 2; 8062306a36Sopenharmony_ci f3 = div - f0 - f1 - f2; 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci N = 4; 8362306a36Sopenharmony_ci f0 = 16; 8462306a36Sopenharmony_ci f1 = 16; 8562306a36Sopenharmony_ci f2 = 16; 8662306a36Sopenharmony_ci f3 = 16; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (f0 == 16) 9062306a36Sopenharmony_ci f0 = 0; 9162306a36Sopenharmony_ci if (f1 == 16) 9262306a36Sopenharmony_ci f1 = 0; 9362306a36Sopenharmony_ci if (f2 == 16) 9462306a36Sopenharmony_ci f2 = 0; 9562306a36Sopenharmony_ci if (f3 == 16) 9662306a36Sopenharmony_ci f3 = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x1D, &utmp); 9962306a36Sopenharmony_ci if (ret) 10062306a36Sopenharmony_ci goto err; 10162306a36Sopenharmony_ci reg1D = utmp; 10262306a36Sopenharmony_ci reg1D &= ~0x03; 10362306a36Sopenharmony_ci reg1D |= N - 1; 10462306a36Sopenharmony_ci reg1E = ((f3 << 4) + f2) & 0xFF; 10562306a36Sopenharmony_ci reg1F = ((f1 << 4) + f0) & 0xFF; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* program and recalibrate demod PLL */ 10862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x05, 0x40); 10962306a36Sopenharmony_ci if (ret) 11062306a36Sopenharmony_ci goto err; 11162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x11, 0x08); 11262306a36Sopenharmony_ci if (ret) 11362306a36Sopenharmony_ci goto err; 11462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x15, reg15); 11562306a36Sopenharmony_ci if (ret) 11662306a36Sopenharmony_ci goto err; 11762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x16, reg16); 11862306a36Sopenharmony_ci if (ret) 11962306a36Sopenharmony_ci goto err; 12062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x1D, reg1D); 12162306a36Sopenharmony_ci if (ret) 12262306a36Sopenharmony_ci goto err; 12362306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x1E, reg1E); 12462306a36Sopenharmony_ci if (ret) 12562306a36Sopenharmony_ci goto err; 12662306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x1F, reg1F); 12762306a36Sopenharmony_ci if (ret) 12862306a36Sopenharmony_ci goto err; 12962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x17, 0xc1); 13062306a36Sopenharmony_ci if (ret) 13162306a36Sopenharmony_ci goto err; 13262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x17, 0x81); 13362306a36Sopenharmony_ci if (ret) 13462306a36Sopenharmony_ci goto err; 13562306a36Sopenharmony_ci usleep_range(5000, 50000); 13662306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x05, 0x00); 13762306a36Sopenharmony_ci if (ret) 13862306a36Sopenharmony_ci goto err; 13962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x11, reg11); 14062306a36Sopenharmony_ci if (ret) 14162306a36Sopenharmony_ci goto err; 14262306a36Sopenharmony_ci usleep_range(5000, 50000); 14362306a36Sopenharmony_cierr: 14462306a36Sopenharmony_ci if (ret) 14562306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev, 15062306a36Sopenharmony_ci u32 tuner_freq_MHz) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv; 15362306a36Sopenharmony_ci u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod; 15462306a36Sopenharmony_ci u8 reg27, reg29, reg42, reg42buf; 15562306a36Sopenharmony_ci unsigned int utmp; 15662306a36Sopenharmony_ci int ret; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci fcry_KHz = 27000; /* in kHz */ 15962306a36Sopenharmony_ci refDiv = 27; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); 16262306a36Sopenharmony_ci if (ret) 16362306a36Sopenharmony_ci goto err; 16462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x31, 0x00); 16562306a36Sopenharmony_ci if (ret) 16662306a36Sopenharmony_ci goto err; 16762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x2c, 0x02); 16862306a36Sopenharmony_ci if (ret) 16962306a36Sopenharmony_ci goto err; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (tuner_freq_MHz >= 1550) { 17262306a36Sopenharmony_ci ucLoDiv1 = 2; 17362306a36Sopenharmony_ci ucLomod1 = 0; 17462306a36Sopenharmony_ci ucLoDiv2 = 2; 17562306a36Sopenharmony_ci ucLomod2 = 0; 17662306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 1380) { 17762306a36Sopenharmony_ci ucLoDiv1 = 3; 17862306a36Sopenharmony_ci ucLomod1 = 16; 17962306a36Sopenharmony_ci ucLoDiv2 = 2; 18062306a36Sopenharmony_ci ucLomod2 = 0; 18162306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 1070) { 18262306a36Sopenharmony_ci ucLoDiv1 = 3; 18362306a36Sopenharmony_ci ucLomod1 = 16; 18462306a36Sopenharmony_ci ucLoDiv2 = 3; 18562306a36Sopenharmony_ci ucLomod2 = 16; 18662306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 1000) { 18762306a36Sopenharmony_ci ucLoDiv1 = 3; 18862306a36Sopenharmony_ci ucLomod1 = 16; 18962306a36Sopenharmony_ci ucLoDiv2 = 4; 19062306a36Sopenharmony_ci ucLomod2 = 64; 19162306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 775) { 19262306a36Sopenharmony_ci ucLoDiv1 = 4; 19362306a36Sopenharmony_ci ucLomod1 = 64; 19462306a36Sopenharmony_ci ucLoDiv2 = 4; 19562306a36Sopenharmony_ci ucLomod2 = 64; 19662306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 700) { 19762306a36Sopenharmony_ci ucLoDiv1 = 6; 19862306a36Sopenharmony_ci ucLomod1 = 48; 19962306a36Sopenharmony_ci ucLoDiv2 = 4; 20062306a36Sopenharmony_ci ucLomod2 = 64; 20162306a36Sopenharmony_ci } else if (tuner_freq_MHz >= 520) { 20262306a36Sopenharmony_ci ucLoDiv1 = 6; 20362306a36Sopenharmony_ci ucLomod1 = 48; 20462306a36Sopenharmony_ci ucLoDiv2 = 6; 20562306a36Sopenharmony_ci ucLomod2 = 48; 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci ucLoDiv1 = 8; 20862306a36Sopenharmony_ci ucLomod1 = 96; 20962306a36Sopenharmony_ci ucLoDiv2 = 8; 21062306a36Sopenharmony_ci ucLomod2 = 96; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv 21462306a36Sopenharmony_ci / fcry_KHz - 1024) / 2; 21562306a36Sopenharmony_ci ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv 21662306a36Sopenharmony_ci / fcry_KHz - 1024) / 2; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F; 21962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x27, reg27); 22062306a36Sopenharmony_ci if (ret) 22162306a36Sopenharmony_ci goto err; 22262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF)); 22362306a36Sopenharmony_ci if (ret) 22462306a36Sopenharmony_ci goto err; 22562306a36Sopenharmony_ci reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f; 22662306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x29, reg29); 22762306a36Sopenharmony_ci if (ret) 22862306a36Sopenharmony_ci goto err; 22962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF)); 23062306a36Sopenharmony_ci if (ret) 23162306a36Sopenharmony_ci goto err; 23262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x2F, 0xf5); 23362306a36Sopenharmony_ci if (ret) 23462306a36Sopenharmony_ci goto err; 23562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x30, 0x05); 23662306a36Sopenharmony_ci if (ret) 23762306a36Sopenharmony_ci goto err; 23862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x1f); 23962306a36Sopenharmony_ci if (ret) 24062306a36Sopenharmony_ci goto err; 24162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x3f); 24262306a36Sopenharmony_ci if (ret) 24362306a36Sopenharmony_ci goto err; 24462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x20); 24562306a36Sopenharmony_ci if (ret) 24662306a36Sopenharmony_ci goto err; 24762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x00); 24862306a36Sopenharmony_ci if (ret) 24962306a36Sopenharmony_ci goto err; 25062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x3e, 0x11); 25162306a36Sopenharmony_ci if (ret) 25262306a36Sopenharmony_ci goto err; 25362306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x2f); 25462306a36Sopenharmony_ci if (ret) 25562306a36Sopenharmony_ci goto err; 25662306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x3f); 25762306a36Sopenharmony_ci if (ret) 25862306a36Sopenharmony_ci goto err; 25962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x10); 26062306a36Sopenharmony_ci if (ret) 26162306a36Sopenharmony_ci goto err; 26262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x00); 26362306a36Sopenharmony_ci if (ret) 26462306a36Sopenharmony_ci goto err; 26562306a36Sopenharmony_ci usleep_range(2000, 50000); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x42, &utmp); 26862306a36Sopenharmony_ci if (ret) 26962306a36Sopenharmony_ci goto err; 27062306a36Sopenharmony_ci reg42 = utmp; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x3e, 0x10); 27362306a36Sopenharmony_ci if (ret) 27462306a36Sopenharmony_ci goto err; 27562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x2f); 27662306a36Sopenharmony_ci if (ret) 27762306a36Sopenharmony_ci goto err; 27862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x08, 0x3f); 27962306a36Sopenharmony_ci if (ret) 28062306a36Sopenharmony_ci goto err; 28162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x10); 28262306a36Sopenharmony_ci if (ret) 28362306a36Sopenharmony_ci goto err; 28462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x09, 0x00); 28562306a36Sopenharmony_ci if (ret) 28662306a36Sopenharmony_ci goto err; 28762306a36Sopenharmony_ci usleep_range(2000, 50000); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x42, &utmp); 29062306a36Sopenharmony_ci if (ret) 29162306a36Sopenharmony_ci goto err; 29262306a36Sopenharmony_ci reg42buf = utmp; 29362306a36Sopenharmony_ci if (reg42buf < reg42) { 29462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x3e, 0x11); 29562306a36Sopenharmony_ci if (ret) 29662306a36Sopenharmony_ci goto err; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci usleep_range(5000, 50000); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x2d, &utmp); 30162306a36Sopenharmony_ci if (ret) 30262306a36Sopenharmony_ci goto err; 30362306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x2d, utmp); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci goto err; 30662306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x2e, &utmp); 30762306a36Sopenharmony_ci if (ret) 30862306a36Sopenharmony_ci goto err; 30962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x2e, utmp); 31062306a36Sopenharmony_ci if (ret) 31162306a36Sopenharmony_ci goto err; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x27, &utmp); 31462306a36Sopenharmony_ci if (ret) 31562306a36Sopenharmony_ci goto err; 31662306a36Sopenharmony_ci reg27 = utmp & 0x70; 31762306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x83, &utmp); 31862306a36Sopenharmony_ci if (ret) 31962306a36Sopenharmony_ci goto err; 32062306a36Sopenharmony_ci if (reg27 == (utmp & 0x70)) { 32162306a36Sopenharmony_ci ucLoDiv = ucLoDiv1; 32262306a36Sopenharmony_ci ulNDiv = ulNDiv1; 32362306a36Sopenharmony_ci ucLomod = ucLomod1 / 16; 32462306a36Sopenharmony_ci } else { 32562306a36Sopenharmony_ci ucLoDiv = ucLoDiv2; 32662306a36Sopenharmony_ci ulNDiv = ulNDiv2; 32762306a36Sopenharmony_ci ucLomod = ucLomod2 / 16; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if ((ucLoDiv == 3) || (ucLoDiv == 6)) { 33162306a36Sopenharmony_ci refDiv = 18; 33262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x36, (refDiv - 8)); 33362306a36Sopenharmony_ci if (ret) 33462306a36Sopenharmony_ci goto err; 33562306a36Sopenharmony_ci ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv 33662306a36Sopenharmony_ci / fcry_KHz - 1024) / 2; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci reg27 = (0x80 + ((ucLomod << 4) & 0x70) 34062306a36Sopenharmony_ci + ((ulNDiv >> 8) & 0x0F)) & 0xFF; 34162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x27, reg27); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci goto err; 34462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF)); 34562306a36Sopenharmony_ci if (ret) 34662306a36Sopenharmony_ci goto err; 34762306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x29, 0x80); 34862306a36Sopenharmony_ci if (ret) 34962306a36Sopenharmony_ci goto err; 35062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x31, 0x03); 35162306a36Sopenharmony_ci if (ret) 35262306a36Sopenharmony_ci goto err; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (ucLoDiv == 3) 35562306a36Sopenharmony_ci utmp = 0xCE; 35662306a36Sopenharmony_ci else 35762306a36Sopenharmony_ci utmp = 0x8A; 35862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x3b, utmp); 35962306a36Sopenharmony_ci if (ret) 36062306a36Sopenharmony_ci goto err; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci dev_dbg(&dev->client->dev, 36562306a36Sopenharmony_ci "actual tune frequency=%d\n", dev->frequency_khz); 36662306a36Sopenharmony_cierr: 36762306a36Sopenharmony_ci if (ret) 36862306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int m88rs6000t_set_bb(struct m88rs6000t_dev *dev, 37362306a36Sopenharmony_ci u32 symbol_rate_KSs, s32 lpf_offset_KHz) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci u32 f3dB; 37662306a36Sopenharmony_ci u8 reg40; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci f3dB = symbol_rate_KSs * 9 / 14 + 2000; 37962306a36Sopenharmony_ci f3dB += lpf_offset_KHz; 38062306a36Sopenharmony_ci f3dB = clamp_val(f3dB, 6000U, 43000U); 38162306a36Sopenharmony_ci reg40 = f3dB / 1000; 38262306a36Sopenharmony_ci return regmap_write(dev->regmap, 0x40, reg40); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int m88rs6000t_set_params(struct dvb_frontend *fe) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 38862306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci s32 lpf_offset_KHz; 39162306a36Sopenharmony_ci u32 realFreq, freq_MHz; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci dev_dbg(&dev->client->dev, 39462306a36Sopenharmony_ci "frequency=%d symbol_rate=%d\n", 39562306a36Sopenharmony_ci c->frequency, c->symbol_rate); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (c->symbol_rate < 5000000) 39862306a36Sopenharmony_ci lpf_offset_KHz = 3000; 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci lpf_offset_KHz = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci realFreq = c->frequency + lpf_offset_KHz; 40362306a36Sopenharmony_ci /* set tuner pll.*/ 40462306a36Sopenharmony_ci freq_MHz = (realFreq + 500) / 1000; 40562306a36Sopenharmony_ci ret = m88rs6000t_set_pll_freq(dev, freq_MHz); 40662306a36Sopenharmony_ci if (ret) 40762306a36Sopenharmony_ci goto err; 40862306a36Sopenharmony_ci ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz); 40962306a36Sopenharmony_ci if (ret) 41062306a36Sopenharmony_ci goto err; 41162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x00, 0x01); 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci goto err; 41462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x00, 0x00); 41562306a36Sopenharmony_ci if (ret) 41662306a36Sopenharmony_ci goto err; 41762306a36Sopenharmony_ci /* set demod mlck */ 41862306a36Sopenharmony_ci ret = m88rs6000t_set_demod_mclk(fe); 41962306a36Sopenharmony_cierr: 42062306a36Sopenharmony_ci if (ret) 42162306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 42262306a36Sopenharmony_ci return ret; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int m88rs6000t_init(struct dvb_frontend *fe) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 42862306a36Sopenharmony_ci int ret; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "%s:\n", __func__); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); 43362306a36Sopenharmony_ci if (ret) 43462306a36Sopenharmony_ci goto err; 43562306a36Sopenharmony_ci usleep_range(5000, 50000); 43662306a36Sopenharmony_ci ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); 43762306a36Sopenharmony_ci if (ret) 43862306a36Sopenharmony_ci goto err; 43962306a36Sopenharmony_ci usleep_range(10000, 50000); 44062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x07, 0x7d); 44162306a36Sopenharmony_cierr: 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 44462306a36Sopenharmony_ci return ret; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int m88rs6000t_sleep(struct dvb_frontend *fe) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "%s:\n", __func__); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x07, 0x6d); 45562306a36Sopenharmony_ci if (ret) { 45662306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci usleep_range(5000, 10000); 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "\n"); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci *frequency = dev->frequency_khz; 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "\n"); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci *frequency = 0; /* Zero-IF */ 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct m88rs6000t_dev *dev = fe->tuner_priv; 48762306a36Sopenharmony_ci unsigned int val, i; 48862306a36Sopenharmony_ci int ret; 48962306a36Sopenharmony_ci u16 gain; 49062306a36Sopenharmony_ci u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290; 49162306a36Sopenharmony_ci u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300; 49262306a36Sopenharmony_ci u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0; 49362306a36Sopenharmony_ci u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0; 49462306a36Sopenharmony_ci u32 RFGS[13] = {0, 245, 266, 268, 270, 285, 49562306a36Sopenharmony_ci 298, 295, 283, 285, 285, 300, 300}; 49662306a36Sopenharmony_ci u32 IFGS[12] = {0, 300, 230, 270, 270, 285, 49762306a36Sopenharmony_ci 295, 285, 290, 295, 295, 310}; 49862306a36Sopenharmony_ci u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290, 49962306a36Sopenharmony_ci 290, 285, 283, 260, 295, 290, 260}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x5A, &val); 50262306a36Sopenharmony_ci if (ret) 50362306a36Sopenharmony_ci goto err; 50462306a36Sopenharmony_ci RF_GC = val & 0x0f; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x5F, &val); 50762306a36Sopenharmony_ci if (ret) 50862306a36Sopenharmony_ci goto err; 50962306a36Sopenharmony_ci IF_GC = val & 0x0f; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x3F, &val); 51262306a36Sopenharmony_ci if (ret) 51362306a36Sopenharmony_ci goto err; 51462306a36Sopenharmony_ci TIA_GC = (val >> 4) & 0x07; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x77, &val); 51762306a36Sopenharmony_ci if (ret) 51862306a36Sopenharmony_ci goto err; 51962306a36Sopenharmony_ci BB_GC = (val >> 4) & 0x0f; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x76, &val); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci goto err; 52462306a36Sopenharmony_ci PGA2_GC = val & 0x3f; 52562306a36Sopenharmony_ci PGA2_cri = PGA2_GC >> 2; 52662306a36Sopenharmony_ci PGA2_crf = PGA2_GC & 0x03; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++) 52962306a36Sopenharmony_ci RFG += RFGS[i]; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (RF_GC == 0) 53262306a36Sopenharmony_ci RFG += 400; 53362306a36Sopenharmony_ci if (RF_GC == 1) 53462306a36Sopenharmony_ci RFG += 300; 53562306a36Sopenharmony_ci if (RF_GC == 2) 53662306a36Sopenharmony_ci RFG += 200; 53762306a36Sopenharmony_ci if (RF_GC == 3) 53862306a36Sopenharmony_ci RFG += 100; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++) 54162306a36Sopenharmony_ci IFG += IFGS[i]; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci TIAG = TIA_GC * TIA_GS; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++) 54662306a36Sopenharmony_ci BBG += BBGS[i]; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci gain = RFG + IFG - TIAG + BBG + PGA2G; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* scale value to 0x0000-0xffff */ 55362306a36Sopenharmony_ci gain = clamp_val(gain, 1000U, 10500U); 55462306a36Sopenharmony_ci *strength = (10500 - gain) * 0xffff / (10500 - 1000); 55562306a36Sopenharmony_cierr: 55662306a36Sopenharmony_ci if (ret) 55762306a36Sopenharmony_ci dev_dbg(&dev->client->dev, "failed=%d\n", ret); 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic const struct dvb_tuner_ops m88rs6000t_tuner_ops = { 56262306a36Sopenharmony_ci .info = { 56362306a36Sopenharmony_ci .name = "Montage M88RS6000 Internal Tuner", 56462306a36Sopenharmony_ci .frequency_min_hz = 950 * MHz, 56562306a36Sopenharmony_ci .frequency_max_hz = 2150 * MHz, 56662306a36Sopenharmony_ci }, 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci .init = m88rs6000t_init, 56962306a36Sopenharmony_ci .sleep = m88rs6000t_sleep, 57062306a36Sopenharmony_ci .set_params = m88rs6000t_set_params, 57162306a36Sopenharmony_ci .get_frequency = m88rs6000t_get_frequency, 57262306a36Sopenharmony_ci .get_if_frequency = m88rs6000t_get_if_frequency, 57362306a36Sopenharmony_ci .get_rf_strength = m88rs6000t_get_rf_strength, 57462306a36Sopenharmony_ci}; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int m88rs6000t_probe(struct i2c_client *client) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct m88rs6000t_config *cfg = client->dev.platform_data; 57962306a36Sopenharmony_ci struct dvb_frontend *fe = cfg->fe; 58062306a36Sopenharmony_ci struct m88rs6000t_dev *dev; 58162306a36Sopenharmony_ci int ret, i; 58262306a36Sopenharmony_ci unsigned int utmp; 58362306a36Sopenharmony_ci static const struct regmap_config regmap_config = { 58462306a36Sopenharmony_ci .reg_bits = 8, 58562306a36Sopenharmony_ci .val_bits = 8, 58662306a36Sopenharmony_ci }; 58762306a36Sopenharmony_ci static const struct m88rs6000t_reg_val reg_vals[] = { 58862306a36Sopenharmony_ci {0x10, 0xfb}, 58962306a36Sopenharmony_ci {0x24, 0x38}, 59062306a36Sopenharmony_ci {0x11, 0x0a}, 59162306a36Sopenharmony_ci {0x12, 0x00}, 59262306a36Sopenharmony_ci {0x2b, 0x1c}, 59362306a36Sopenharmony_ci {0x44, 0x48}, 59462306a36Sopenharmony_ci {0x54, 0x24}, 59562306a36Sopenharmony_ci {0x55, 0x06}, 59662306a36Sopenharmony_ci {0x59, 0x00}, 59762306a36Sopenharmony_ci {0x5b, 0x4c}, 59862306a36Sopenharmony_ci {0x60, 0x8b}, 59962306a36Sopenharmony_ci {0x61, 0xf4}, 60062306a36Sopenharmony_ci {0x65, 0x07}, 60162306a36Sopenharmony_ci {0x6d, 0x6f}, 60262306a36Sopenharmony_ci {0x6e, 0x31}, 60362306a36Sopenharmony_ci {0x3c, 0xf3}, 60462306a36Sopenharmony_ci {0x37, 0x0f}, 60562306a36Sopenharmony_ci {0x48, 0x28}, 60662306a36Sopenharmony_ci {0x49, 0xd8}, 60762306a36Sopenharmony_ci {0x70, 0x66}, 60862306a36Sopenharmony_ci {0x71, 0xCF}, 60962306a36Sopenharmony_ci {0x72, 0x81}, 61062306a36Sopenharmony_ci {0x73, 0xA7}, 61162306a36Sopenharmony_ci {0x74, 0x4F}, 61262306a36Sopenharmony_ci {0x75, 0xFC}, 61362306a36Sopenharmony_ci }; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 61662306a36Sopenharmony_ci if (!dev) { 61762306a36Sopenharmony_ci ret = -ENOMEM; 61862306a36Sopenharmony_ci dev_err(&client->dev, "kzalloc() failed\n"); 61962306a36Sopenharmony_ci goto err; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config)); 62362306a36Sopenharmony_ci dev->client = client; 62462306a36Sopenharmony_ci dev->regmap = devm_regmap_init_i2c(client, ®map_config); 62562306a36Sopenharmony_ci if (IS_ERR(dev->regmap)) { 62662306a36Sopenharmony_ci ret = PTR_ERR(dev->regmap); 62762306a36Sopenharmony_ci goto err; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08); 63162306a36Sopenharmony_ci if (ret) 63262306a36Sopenharmony_ci goto err; 63362306a36Sopenharmony_ci usleep_range(5000, 50000); 63462306a36Sopenharmony_ci ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01); 63562306a36Sopenharmony_ci if (ret) 63662306a36Sopenharmony_ci goto err; 63762306a36Sopenharmony_ci usleep_range(10000, 50000); 63862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x07, 0x7d); 63962306a36Sopenharmony_ci if (ret) 64062306a36Sopenharmony_ci goto err; 64162306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x04, 0x01); 64262306a36Sopenharmony_ci if (ret) 64362306a36Sopenharmony_ci goto err; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* check tuner chip id */ 64662306a36Sopenharmony_ci ret = regmap_read(dev->regmap, 0x01, &utmp); 64762306a36Sopenharmony_ci if (ret) 64862306a36Sopenharmony_ci goto err; 64962306a36Sopenharmony_ci dev_info(&dev->client->dev, "chip_id=%02x\n", utmp); 65062306a36Sopenharmony_ci if (utmp != 0x64) { 65162306a36Sopenharmony_ci ret = -ENODEV; 65262306a36Sopenharmony_ci goto err; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* tuner init. */ 65662306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x05, 0x40); 65762306a36Sopenharmony_ci if (ret) 65862306a36Sopenharmony_ci goto err; 65962306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x11, 0x08); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci goto err; 66262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x15, 0x6c); 66362306a36Sopenharmony_ci if (ret) 66462306a36Sopenharmony_ci goto err; 66562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x17, 0xc1); 66662306a36Sopenharmony_ci if (ret) 66762306a36Sopenharmony_ci goto err; 66862306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x17, 0x81); 66962306a36Sopenharmony_ci if (ret) 67062306a36Sopenharmony_ci goto err; 67162306a36Sopenharmony_ci usleep_range(10000, 50000); 67262306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x05, 0x00); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci goto err; 67562306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 0x11, 0x0a); 67662306a36Sopenharmony_ci if (ret) 67762306a36Sopenharmony_ci goto err; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { 68062306a36Sopenharmony_ci ret = regmap_write(dev->regmap, 68162306a36Sopenharmony_ci reg_vals[i].reg, reg_vals[i].val); 68262306a36Sopenharmony_ci if (ret) 68362306a36Sopenharmony_ci goto err; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n"); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci fe->tuner_priv = dev; 68962306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops, 69062306a36Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 69162306a36Sopenharmony_ci i2c_set_clientdata(client, dev); 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_cierr: 69462306a36Sopenharmony_ci dev_dbg(&client->dev, "failed=%d\n", ret); 69562306a36Sopenharmony_ci kfree(dev); 69662306a36Sopenharmony_ci return ret; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic void m88rs6000t_remove(struct i2c_client *client) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct m88rs6000t_dev *dev = i2c_get_clientdata(client); 70262306a36Sopenharmony_ci struct dvb_frontend *fe = dev->cfg.fe; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci dev_dbg(&client->dev, "\n"); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); 70762306a36Sopenharmony_ci fe->tuner_priv = NULL; 70862306a36Sopenharmony_ci kfree(dev); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic const struct i2c_device_id m88rs6000t_id[] = { 71262306a36Sopenharmony_ci {"m88rs6000t", 0}, 71362306a36Sopenharmony_ci {} 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, m88rs6000t_id); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic struct i2c_driver m88rs6000t_driver = { 71862306a36Sopenharmony_ci .driver = { 71962306a36Sopenharmony_ci .name = "m88rs6000t", 72062306a36Sopenharmony_ci }, 72162306a36Sopenharmony_ci .probe = m88rs6000t_probe, 72262306a36Sopenharmony_ci .remove = m88rs6000t_remove, 72362306a36Sopenharmony_ci .id_table = m88rs6000t_id, 72462306a36Sopenharmony_ci}; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cimodule_i2c_driver(m88rs6000t_driver); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); 72962306a36Sopenharmony_ciMODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver"); 73062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 731