fc0011.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Fitipower FC0011 tuner driver
  4. *
  5. * Copyright (C) 2012 Michael Buesch <m@bues.ch>
  6. *
  7. * Derived from FC0012 tuner driver:
  8. * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
  9. */
  10. #include "fc0011.h"
  11. /* Tuner registers */
  12. enum {
  13. FC11_REG_0,
  14. FC11_REG_FA, /* FA */
  15. FC11_REG_FP, /* FP */
  16. FC11_REG_XINHI, /* XIN high 8 bit */
  17. FC11_REG_XINLO, /* XIN low 8 bit */
  18. FC11_REG_VCO, /* VCO */
  19. FC11_REG_VCOSEL, /* VCO select */
  20. FC11_REG_7, /* Unknown tuner reg 7 */
  21. FC11_REG_8, /* Unknown tuner reg 8 */
  22. FC11_REG_9,
  23. FC11_REG_10, /* Unknown tuner reg 10 */
  24. FC11_REG_11, /* Unknown tuner reg 11 */
  25. FC11_REG_12,
  26. FC11_REG_RCCAL, /* RC calibrate */
  27. FC11_REG_VCOCAL, /* VCO calibrate */
  28. FC11_REG_15,
  29. FC11_REG_16, /* Unknown tuner reg 16 */
  30. FC11_REG_17,
  31. FC11_NR_REGS, /* Number of registers */
  32. };
  33. enum FC11_REG_VCOSEL_bits {
  34. FC11_VCOSEL_2 = 0x08, /* VCO select 2 */
  35. FC11_VCOSEL_1 = 0x10, /* VCO select 1 */
  36. FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */
  37. FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */
  38. FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */
  39. };
  40. enum FC11_REG_RCCAL_bits {
  41. FC11_RCCAL_FORCE = 0x10, /* force */
  42. };
  43. enum FC11_REG_VCOCAL_bits {
  44. FC11_VCOCAL_RUN = 0, /* VCO calibration run */
  45. FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */
  46. FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */
  47. FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */
  48. };
  49. struct fc0011_priv {
  50. struct i2c_adapter *i2c;
  51. u8 addr;
  52. u32 frequency;
  53. u32 bandwidth;
  54. };
  55. static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
  56. {
  57. u8 buf[2] = { reg, val };
  58. struct i2c_msg msg = { .addr = priv->addr,
  59. .flags = 0, .buf = buf, .len = 2 };
  60. if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
  61. dev_err(&priv->i2c->dev,
  62. "I2C write reg failed, reg: %02x, val: %02x\n",
  63. reg, val);
  64. return -EIO;
  65. }
  66. return 0;
  67. }
  68. static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
  69. {
  70. u8 dummy;
  71. struct i2c_msg msg[2] = {
  72. { .addr = priv->addr,
  73. .flags = 0, .buf = &reg, .len = 1 },
  74. { .addr = priv->addr,
  75. .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
  76. };
  77. if (i2c_transfer(priv->i2c, msg, 2) != 2) {
  78. dev_err(&priv->i2c->dev,
  79. "I2C read failed, reg: %02x\n", reg);
  80. return -EIO;
  81. }
  82. return 0;
  83. }
  84. static void fc0011_release(struct dvb_frontend *fe)
  85. {
  86. kfree(fe->tuner_priv);
  87. fe->tuner_priv = NULL;
  88. }
  89. static int fc0011_init(struct dvb_frontend *fe)
  90. {
  91. struct fc0011_priv *priv = fe->tuner_priv;
  92. int err;
  93. if (WARN_ON(!fe->callback))
  94. return -EINVAL;
  95. err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
  96. FC0011_FE_CALLBACK_POWER, priv->addr);
  97. if (err) {
  98. dev_err(&priv->i2c->dev, "Power-on callback failed\n");
  99. return err;
  100. }
  101. err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
  102. FC0011_FE_CALLBACK_RESET, priv->addr);
  103. if (err) {
  104. dev_err(&priv->i2c->dev, "Reset callback failed\n");
  105. return err;
  106. }
  107. return 0;
  108. }
  109. /* Initiate VCO calibration */
  110. static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
  111. {
  112. int err;
  113. err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
  114. if (err)
  115. return err;
  116. err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
  117. if (err)
  118. return err;
  119. return 0;
  120. }
  121. /* Read VCO calibration value */
  122. static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
  123. {
  124. int err;
  125. err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
  126. if (err)
  127. return err;
  128. usleep_range(10000, 20000);
  129. err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
  130. if (err)
  131. return err;
  132. return 0;
  133. }
  134. static int fc0011_set_params(struct dvb_frontend *fe)
  135. {
  136. struct dtv_frontend_properties *p = &fe->dtv_property_cache;
  137. struct fc0011_priv *priv = fe->tuner_priv;
  138. int err;
  139. unsigned int i, vco_retries;
  140. u32 freq = p->frequency / 1000;
  141. u32 bandwidth = p->bandwidth_hz / 1000;
  142. u32 fvco, xin, frac, xdiv, xdivr;
  143. u8 fa, fp, vco_sel, vco_cal;
  144. u8 regs[FC11_NR_REGS] = { };
  145. regs[FC11_REG_7] = 0x0F;
  146. regs[FC11_REG_8] = 0x3E;
  147. regs[FC11_REG_10] = 0xB8;
  148. regs[FC11_REG_11] = 0x80;
  149. regs[FC11_REG_RCCAL] = 0x04;
  150. err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
  151. err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
  152. err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
  153. err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
  154. err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
  155. if (err)
  156. return -EIO;
  157. /* Set VCO freq and VCO div */
  158. if (freq < 54000) {
  159. fvco = freq * 64;
  160. regs[FC11_REG_VCO] = 0x82;
  161. } else if (freq < 108000) {
  162. fvco = freq * 32;
  163. regs[FC11_REG_VCO] = 0x42;
  164. } else if (freq < 216000) {
  165. fvco = freq * 16;
  166. regs[FC11_REG_VCO] = 0x22;
  167. } else if (freq < 432000) {
  168. fvco = freq * 8;
  169. regs[FC11_REG_VCO] = 0x12;
  170. } else {
  171. fvco = freq * 4;
  172. regs[FC11_REG_VCO] = 0x0A;
  173. }
  174. /* Calc XIN. The PLL reference frequency is 18 MHz. */
  175. xdiv = fvco / 18000;
  176. WARN_ON(xdiv > 0xFF);
  177. frac = fvco - xdiv * 18000;
  178. frac = (frac << 15) / 18000;
  179. if (frac >= 16384)
  180. frac += 32786;
  181. if (!frac)
  182. xin = 0;
  183. else
  184. xin = clamp_t(u32, frac, 512, 65024);
  185. regs[FC11_REG_XINHI] = xin >> 8;
  186. regs[FC11_REG_XINLO] = xin;
  187. /* Calc FP and FA */
  188. xdivr = xdiv;
  189. if (fvco - xdiv * 18000 >= 9000)
  190. xdivr += 1; /* round */
  191. fp = xdivr / 8;
  192. fa = xdivr - fp * 8;
  193. if (fa < 2) {
  194. fp -= 1;
  195. fa += 8;
  196. }
  197. if (fp > 0x1F) {
  198. fp = 0x1F;
  199. fa = 0xF;
  200. }
  201. if (fa >= fp) {
  202. dev_warn(&priv->i2c->dev,
  203. "fa %02X >= fp %02X, but trying to continue\n",
  204. (unsigned int)(u8)fa, (unsigned int)(u8)fp);
  205. }
  206. regs[FC11_REG_FA] = fa;
  207. regs[FC11_REG_FP] = fp;
  208. /* Select bandwidth */
  209. switch (bandwidth) {
  210. case 8000:
  211. break;
  212. case 7000:
  213. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
  214. break;
  215. default:
  216. dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n",
  217. bandwidth);
  218. bandwidth = 6000;
  219. fallthrough;
  220. case 6000:
  221. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
  222. break;
  223. }
  224. /* Pre VCO select */
  225. if (fvco < 2320000) {
  226. vco_sel = 0;
  227. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  228. } else if (fvco < 3080000) {
  229. vco_sel = 1;
  230. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  231. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
  232. } else {
  233. vco_sel = 2;
  234. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  235. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
  236. }
  237. /* Fix for low freqs */
  238. if (freq < 45000) {
  239. regs[FC11_REG_FA] = 0x6;
  240. regs[FC11_REG_FP] = 0x11;
  241. }
  242. /* Clock out fix */
  243. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
  244. /* Write the cached registers */
  245. for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
  246. err = fc0011_writereg(priv, i, regs[i]);
  247. if (err)
  248. return err;
  249. }
  250. /* VCO calibration */
  251. err = fc0011_vcocal_trigger(priv);
  252. if (err)
  253. return err;
  254. err = fc0011_vcocal_read(priv, &vco_cal);
  255. if (err)
  256. return err;
  257. vco_retries = 0;
  258. while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
  259. /* Reset the tuner and try again */
  260. err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
  261. FC0011_FE_CALLBACK_RESET, priv->addr);
  262. if (err) {
  263. dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
  264. return err;
  265. }
  266. /* Reinit tuner config */
  267. err = 0;
  268. for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
  269. err |= fc0011_writereg(priv, i, regs[i]);
  270. err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
  271. err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
  272. err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
  273. err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
  274. err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
  275. if (err)
  276. return -EIO;
  277. /* VCO calibration */
  278. err = fc0011_vcocal_trigger(priv);
  279. if (err)
  280. return err;
  281. err = fc0011_vcocal_read(priv, &vco_cal);
  282. if (err)
  283. return err;
  284. vco_retries++;
  285. }
  286. if (!(vco_cal & FC11_VCOCAL_OK)) {
  287. dev_err(&priv->i2c->dev,
  288. "Failed to read VCO calibration value (got %02X)\n",
  289. (unsigned int)vco_cal);
  290. return -EIO;
  291. }
  292. vco_cal &= FC11_VCOCAL_VALUEMASK;
  293. switch (vco_sel) {
  294. default:
  295. WARN_ON(1);
  296. return -EINVAL;
  297. case 0:
  298. if (vco_cal < 8) {
  299. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  300. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
  301. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  302. regs[FC11_REG_VCOSEL]);
  303. if (err)
  304. return err;
  305. err = fc0011_vcocal_trigger(priv);
  306. if (err)
  307. return err;
  308. } else {
  309. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  310. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  311. regs[FC11_REG_VCOSEL]);
  312. if (err)
  313. return err;
  314. }
  315. break;
  316. case 1:
  317. if (vco_cal < 5) {
  318. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  319. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
  320. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  321. regs[FC11_REG_VCOSEL]);
  322. if (err)
  323. return err;
  324. err = fc0011_vcocal_trigger(priv);
  325. if (err)
  326. return err;
  327. } else if (vco_cal <= 48) {
  328. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  329. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
  330. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  331. regs[FC11_REG_VCOSEL]);
  332. if (err)
  333. return err;
  334. } else {
  335. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  336. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  337. regs[FC11_REG_VCOSEL]);
  338. if (err)
  339. return err;
  340. err = fc0011_vcocal_trigger(priv);
  341. if (err)
  342. return err;
  343. }
  344. break;
  345. case 2:
  346. if (vco_cal > 53) {
  347. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  348. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
  349. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  350. regs[FC11_REG_VCOSEL]);
  351. if (err)
  352. return err;
  353. err = fc0011_vcocal_trigger(priv);
  354. if (err)
  355. return err;
  356. } else {
  357. regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
  358. regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
  359. err = fc0011_writereg(priv, FC11_REG_VCOSEL,
  360. regs[FC11_REG_VCOSEL]);
  361. if (err)
  362. return err;
  363. }
  364. break;
  365. }
  366. err = fc0011_vcocal_read(priv, NULL);
  367. if (err)
  368. return err;
  369. usleep_range(10000, 50000);
  370. err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
  371. if (err)
  372. return err;
  373. regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
  374. err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
  375. if (err)
  376. return err;
  377. regs[FC11_REG_16] = 0xB;
  378. err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]);
  379. if (err)
  380. return err;
  381. dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n",
  382. (unsigned int)regs[FC11_REG_FA],
  383. (unsigned int)regs[FC11_REG_FP],
  384. (unsigned int)regs[FC11_REG_XINHI],
  385. (unsigned int)regs[FC11_REG_XINLO],
  386. (unsigned int)regs[FC11_REG_VCO],
  387. (unsigned int)regs[FC11_REG_VCOSEL],
  388. (unsigned int)vco_cal, vco_retries,
  389. (unsigned int)bandwidth);
  390. priv->frequency = p->frequency;
  391. priv->bandwidth = p->bandwidth_hz;
  392. return 0;
  393. }
  394. static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  395. {
  396. struct fc0011_priv *priv = fe->tuner_priv;
  397. *frequency = priv->frequency;
  398. return 0;
  399. }
  400. static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
  401. {
  402. *frequency = 0;
  403. return 0;
  404. }
  405. static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
  406. {
  407. struct fc0011_priv *priv = fe->tuner_priv;
  408. *bandwidth = priv->bandwidth;
  409. return 0;
  410. }
  411. static const struct dvb_tuner_ops fc0011_tuner_ops = {
  412. .info = {
  413. .name = "Fitipower FC0011",
  414. .frequency_min_hz = 45 * MHz,
  415. .frequency_max_hz = 1000 * MHz,
  416. },
  417. .release = fc0011_release,
  418. .init = fc0011_init,
  419. .set_params = fc0011_set_params,
  420. .get_frequency = fc0011_get_frequency,
  421. .get_if_frequency = fc0011_get_if_frequency,
  422. .get_bandwidth = fc0011_get_bandwidth,
  423. };
  424. struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
  425. struct i2c_adapter *i2c,
  426. const struct fc0011_config *config)
  427. {
  428. struct fc0011_priv *priv;
  429. priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
  430. if (!priv)
  431. return NULL;
  432. priv->i2c = i2c;
  433. priv->addr = config->i2c_address;
  434. fe->tuner_priv = priv;
  435. fe->ops.tuner_ops = fc0011_tuner_ops;
  436. dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
  437. return fe;
  438. }
  439. EXPORT_SYMBOL(fc0011_attach);
  440. MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
  441. MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
  442. MODULE_LICENSE("GPL");