cx24113.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Driver for Conexant CX24113/CX24128 Tuner (Satellite)
  4. *
  5. * Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
  6. *
  7. * Developed for BBTI / Technisat
  8. */
  9. #include <linux/slab.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <media/dvb_frontend.h>
  14. #include "cx24113.h"
  15. static int debug;
  16. #define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
  17. #define cx_err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
  18. #define dprintk(args...) \
  19. do { \
  20. if (debug) { \
  21. printk(KERN_DEBUG "CX24113: %s: ", __func__); \
  22. printk(args); \
  23. } \
  24. } while (0)
  25. struct cx24113_state {
  26. struct i2c_adapter *i2c;
  27. const struct cx24113_config *config;
  28. #define REV_CX24113 0x23
  29. u8 rev;
  30. u8 ver;
  31. u8 icp_mode:1;
  32. #define ICP_LEVEL1 0
  33. #define ICP_LEVEL2 1
  34. #define ICP_LEVEL3 2
  35. #define ICP_LEVEL4 3
  36. u8 icp_man:2;
  37. u8 icp_auto_low:2;
  38. u8 icp_auto_mlow:2;
  39. u8 icp_auto_mhi:2;
  40. u8 icp_auto_hi:2;
  41. u8 icp_dig;
  42. #define LNA_MIN_GAIN 0
  43. #define LNA_MID_GAIN 1
  44. #define LNA_MAX_GAIN 2
  45. u8 lna_gain:2;
  46. u8 acp_on:1;
  47. u8 vco_mode:2;
  48. u8 vco_shift:1;
  49. #define VCOBANDSEL_6 0x80
  50. #define VCOBANDSEL_5 0x01
  51. #define VCOBANDSEL_4 0x02
  52. #define VCOBANDSEL_3 0x04
  53. #define VCOBANDSEL_2 0x08
  54. #define VCOBANDSEL_1 0x10
  55. u8 vco_band;
  56. #define VCODIV4 4
  57. #define VCODIV2 2
  58. u8 vcodiv;
  59. u8 bs_delay:4;
  60. u16 bs_freqcnt:13;
  61. u16 bs_rdiv;
  62. u8 prescaler_mode:1;
  63. u8 rfvga_bias_ctrl;
  64. s16 tuner_gain_thres;
  65. u8 gain_level;
  66. u32 frequency;
  67. u8 refdiv;
  68. u8 Fwindow_enabled;
  69. };
  70. static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
  71. {
  72. u8 buf[] = { reg, data };
  73. struct i2c_msg msg = { .addr = state->config->i2c_addr,
  74. .flags = 0, .buf = buf, .len = 2 };
  75. int err = i2c_transfer(state->i2c, &msg, 1);
  76. if (err != 1) {
  77. printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x, data == 0x%02x)\n",
  78. __func__, err, reg, data);
  79. return err;
  80. }
  81. return 0;
  82. }
  83. static int cx24113_readreg(struct cx24113_state *state, u8 reg)
  84. {
  85. int ret;
  86. u8 b;
  87. struct i2c_msg msg[] = {
  88. { .addr = state->config->i2c_addr,
  89. .flags = 0, .buf = &reg, .len = 1 },
  90. { .addr = state->config->i2c_addr,
  91. .flags = I2C_M_RD, .buf = &b, .len = 1 }
  92. };
  93. ret = i2c_transfer(state->i2c, msg, 2);
  94. if (ret != 2) {
  95. printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
  96. __func__, reg, ret);
  97. return ret;
  98. }
  99. return b;
  100. }
  101. static void cx24113_set_parameters(struct cx24113_state *state)
  102. {
  103. u8 r;
  104. r = cx24113_readreg(state, 0x10) & 0x82;
  105. r |= state->icp_mode;
  106. r |= state->icp_man << 4;
  107. r |= state->icp_dig << 2;
  108. r |= state->prescaler_mode << 5;
  109. cx24113_writereg(state, 0x10, r);
  110. r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
  111. | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
  112. cx24113_writereg(state, 0x11, r);
  113. if (state->rev == REV_CX24113) {
  114. r = cx24113_readreg(state, 0x20) & 0xec;
  115. r |= state->lna_gain;
  116. r |= state->rfvga_bias_ctrl << 4;
  117. cx24113_writereg(state, 0x20, r);
  118. }
  119. r = cx24113_readreg(state, 0x12) & 0x03;
  120. r |= state->acp_on << 2;
  121. r |= state->bs_delay << 4;
  122. cx24113_writereg(state, 0x12, r);
  123. r = cx24113_readreg(state, 0x18) & 0x40;
  124. r |= state->vco_shift;
  125. if (state->vco_band == VCOBANDSEL_6)
  126. r |= (1 << 7);
  127. else
  128. r |= (state->vco_band << 1);
  129. cx24113_writereg(state, 0x18, r);
  130. r = cx24113_readreg(state, 0x14) & 0x20;
  131. r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
  132. cx24113_writereg(state, 0x14, r);
  133. cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
  134. cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
  135. r = (cx24113_readreg(state, 0x17) & 0x0f) |
  136. ((state->bs_rdiv & 0x0f) << 4);
  137. cx24113_writereg(state, 0x17, r);
  138. }
  139. #define VGA_0 0x00
  140. #define VGA_1 0x04
  141. #define VGA_2 0x02
  142. #define VGA_3 0x06
  143. #define VGA_4 0x01
  144. #define VGA_5 0x05
  145. #define VGA_6 0x03
  146. #define VGA_7 0x07
  147. #define RFVGA_0 0x00
  148. #define RFVGA_1 0x01
  149. #define RFVGA_2 0x02
  150. #define RFVGA_3 0x03
  151. static int cx24113_set_gain_settings(struct cx24113_state *state,
  152. s16 power_estimation)
  153. {
  154. u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
  155. vga = cx24113_readreg(state, 0x1f) & 0x3f,
  156. rfvga = cx24113_readreg(state, 0x20) & 0xf3;
  157. u8 gain_level = power_estimation >= state->tuner_gain_thres;
  158. dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
  159. power_estimation, state->tuner_gain_thres,
  160. state->gain_level, gain_level);
  161. if (gain_level == state->gain_level)
  162. return 0; /* nothing to be done */
  163. ampout |= 0xf;
  164. if (gain_level) {
  165. rfvga |= RFVGA_0 << 2;
  166. vga |= (VGA_7 << 3) | VGA_7;
  167. } else {
  168. rfvga |= RFVGA_2 << 2;
  169. vga |= (VGA_6 << 3) | VGA_2;
  170. }
  171. state->gain_level = gain_level;
  172. cx24113_writereg(state, 0x1d, ampout);
  173. cx24113_writereg(state, 0x1f, vga);
  174. cx24113_writereg(state, 0x20, rfvga);
  175. return 1; /* did something */
  176. }
  177. static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
  178. {
  179. u8 xtal = cx24113_readreg(state, 0x02);
  180. if (state->rev == 0x43 && state->vcodiv == VCODIV4)
  181. high = 1;
  182. xtal &= ~0x2;
  183. if (high)
  184. xtal |= high << 1;
  185. return cx24113_writereg(state, 0x02, xtal);
  186. }
  187. static int cx24113_enable(struct cx24113_state *state, u8 enable)
  188. {
  189. u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
  190. if (state->rev == REV_CX24113)
  191. r21 |= (1 << 1);
  192. return cx24113_writereg(state, 0x21, r21);
  193. }
  194. static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
  195. {
  196. u8 r;
  197. if (bandwidth_khz <= 19000)
  198. r = 0x03 << 6;
  199. else if (bandwidth_khz <= 25000)
  200. r = 0x02 << 6;
  201. else
  202. r = 0x01 << 6;
  203. dprintk("bandwidth to be set: %d\n", bandwidth_khz);
  204. bandwidth_khz *= 10;
  205. bandwidth_khz -= 10000;
  206. bandwidth_khz /= 1000;
  207. bandwidth_khz += 5;
  208. bandwidth_khz /= 10;
  209. dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
  210. r |= bandwidth_khz & 0x3f;
  211. return cx24113_writereg(state, 0x1e, r);
  212. }
  213. static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
  214. {
  215. u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
  216. return cx24113_writereg(state, 0x10, r);
  217. }
  218. static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
  219. {
  220. struct cx24113_state *state = fe->tuner_priv;
  221. u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
  222. if (r)
  223. *status |= TUNER_STATUS_LOCKED;
  224. dprintk("PLL locked: %d\n", r);
  225. return 0;
  226. }
  227. static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
  228. {
  229. if (state->rev == 0x43 && state->vcodiv == VCODIV4)
  230. refdiv = 2;
  231. return state->refdiv = refdiv;
  232. }
  233. static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
  234. {
  235. s32 N;
  236. s64 F;
  237. u64 dividend;
  238. u8 R, r;
  239. u8 vcodiv;
  240. u8 factor;
  241. s32 freq_hz = state->frequency * 1000;
  242. if (state->config->xtal_khz < 20000)
  243. factor = 1;
  244. else
  245. factor = 2;
  246. if (state->rev == REV_CX24113) {
  247. if (state->frequency >= 1100000)
  248. vcodiv = VCODIV2;
  249. else
  250. vcodiv = VCODIV4;
  251. } else {
  252. if (state->frequency >= 1165000)
  253. vcodiv = VCODIV2;
  254. else
  255. vcodiv = VCODIV4;
  256. }
  257. state->vcodiv = vcodiv;
  258. dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
  259. R = 0;
  260. do {
  261. R = cx24113_set_ref_div(state, R + 1);
  262. /* calculate tuner PLL settings: */
  263. N = (freq_hz / 100 * vcodiv) * R;
  264. N /= (state->config->xtal_khz) * factor * 2;
  265. N += 5; /* For round up. */
  266. N /= 10;
  267. N -= 32;
  268. } while (N < 6 && R < 3);
  269. if (N < 6) {
  270. cx_err("strange frequency: N < 6\n");
  271. return;
  272. }
  273. F = freq_hz;
  274. F *= (u64) (R * vcodiv * 262144);
  275. dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
  276. /* do_div needs an u64 as first argument */
  277. dividend = F;
  278. do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
  279. F = dividend;
  280. dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
  281. F -= (N + 32) * 262144;
  282. dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
  283. if (state->Fwindow_enabled) {
  284. if (F > (262144 / 2 - 1638))
  285. F = 262144 / 2 - 1638;
  286. if (F < (-262144 / 2 + 1638))
  287. F = -262144 / 2 + 1638;
  288. if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
  289. F = 0;
  290. r = cx24113_readreg(state, 0x10);
  291. cx24113_writereg(state, 0x10, r | (1 << 6));
  292. }
  293. }
  294. dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
  295. *n = (u16) N;
  296. *f = (s32) F;
  297. }
  298. static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
  299. {
  300. u8 reg;
  301. cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
  302. reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
  303. cx24113_writereg(state, 0x1a, reg);
  304. cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
  305. reg = cx24113_readreg(state, 0x1c) & 0x1f;
  306. cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
  307. cx24113_set_Fref(state, r - 1);
  308. }
  309. static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
  310. {
  311. u8 r = 1; /* or 2 */
  312. u16 n = 6;
  313. s32 f = 0;
  314. r = cx24113_readreg(state, 0x14);
  315. cx24113_writereg(state, 0x14, r & 0x3f);
  316. r = cx24113_readreg(state, 0x10);
  317. cx24113_writereg(state, 0x10, r & 0xbf);
  318. state->frequency = frequency;
  319. dprintk("tuning to frequency: %d\n", frequency);
  320. cx24113_calc_pll_nf(state, &n, &f);
  321. cx24113_set_nfr(state, n, f, state->refdiv);
  322. r = cx24113_readreg(state, 0x18) & 0xbf;
  323. if (state->vcodiv != VCODIV2)
  324. r |= 1 << 6;
  325. cx24113_writereg(state, 0x18, r);
  326. /* The need for this sleep is not clear. But helps in some cases */
  327. msleep(5);
  328. r = cx24113_readreg(state, 0x1c) & 0xef;
  329. cx24113_writereg(state, 0x1c, r | (1 << 4));
  330. return 0;
  331. }
  332. static int cx24113_init(struct dvb_frontend *fe)
  333. {
  334. struct cx24113_state *state = fe->tuner_priv;
  335. int ret;
  336. state->tuner_gain_thres = -50;
  337. state->gain_level = 255; /* to force a gain-setting initialization */
  338. state->icp_mode = 0;
  339. if (state->config->xtal_khz < 11000) {
  340. state->icp_auto_hi = ICP_LEVEL4;
  341. state->icp_auto_mhi = ICP_LEVEL4;
  342. state->icp_auto_mlow = ICP_LEVEL3;
  343. state->icp_auto_low = ICP_LEVEL3;
  344. } else {
  345. state->icp_auto_hi = ICP_LEVEL4;
  346. state->icp_auto_mhi = ICP_LEVEL4;
  347. state->icp_auto_mlow = ICP_LEVEL3;
  348. state->icp_auto_low = ICP_LEVEL2;
  349. }
  350. state->icp_dig = ICP_LEVEL3;
  351. state->icp_man = ICP_LEVEL1;
  352. state->acp_on = 1;
  353. state->vco_mode = 0;
  354. state->vco_shift = 0;
  355. state->vco_band = VCOBANDSEL_1;
  356. state->bs_delay = 8;
  357. state->bs_freqcnt = 0x0fff;
  358. state->bs_rdiv = 0x0fff;
  359. state->prescaler_mode = 0;
  360. state->lna_gain = LNA_MAX_GAIN;
  361. state->rfvga_bias_ctrl = 1;
  362. state->Fwindow_enabled = 1;
  363. cx24113_set_Fref(state, 0);
  364. cx24113_enable(state, 0x3d);
  365. cx24113_set_parameters(state);
  366. cx24113_set_gain_settings(state, -30);
  367. cx24113_set_bandwidth(state, 18025);
  368. cx24113_set_clk_inversion(state, 1);
  369. if (state->config->xtal_khz >= 40000)
  370. ret = cx24113_writereg(state, 0x02,
  371. (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
  372. else
  373. ret = cx24113_writereg(state, 0x02,
  374. (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
  375. return ret;
  376. }
  377. static int cx24113_set_params(struct dvb_frontend *fe)
  378. {
  379. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  380. struct cx24113_state *state = fe->tuner_priv;
  381. /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
  382. u32 roll_off = 675;
  383. u32 bw;
  384. bw = ((c->symbol_rate/100) * roll_off) / 1000;
  385. bw += (10000000/100) + 5;
  386. bw /= 10;
  387. bw += 1000;
  388. cx24113_set_bandwidth(state, bw);
  389. cx24113_set_frequency(state, c->frequency);
  390. msleep(5);
  391. return cx24113_get_status(fe, &bw);
  392. }
  393. static s8 cx24113_agc_table[2][10] = {
  394. {-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
  395. {-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
  396. };
  397. void cx24113_agc_callback(struct dvb_frontend *fe)
  398. {
  399. struct cx24113_state *state = fe->tuner_priv;
  400. s16 s, i;
  401. if (!fe->ops.read_signal_strength)
  402. return;
  403. do {
  404. /* this only works with the current CX24123 implementation */
  405. fe->ops.read_signal_strength(fe, (u16 *) &s);
  406. s >>= 8;
  407. dprintk("signal strength: %d\n", s);
  408. for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
  409. if (cx24113_agc_table[state->gain_level][i] > s)
  410. break;
  411. s = -25 - i*5;
  412. } while (cx24113_set_gain_settings(state, s));
  413. }
  414. EXPORT_SYMBOL(cx24113_agc_callback);
  415. static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  416. {
  417. struct cx24113_state *state = fe->tuner_priv;
  418. *frequency = state->frequency;
  419. return 0;
  420. }
  421. static void cx24113_release(struct dvb_frontend *fe)
  422. {
  423. struct cx24113_state *state = fe->tuner_priv;
  424. dprintk("\n");
  425. fe->tuner_priv = NULL;
  426. kfree(state);
  427. }
  428. static const struct dvb_tuner_ops cx24113_tuner_ops = {
  429. .info = {
  430. .name = "Conexant CX24113",
  431. .frequency_min_hz = 950 * MHz,
  432. .frequency_max_hz = 2150 * MHz,
  433. .frequency_step_hz = 125 * kHz,
  434. },
  435. .release = cx24113_release,
  436. .init = cx24113_init,
  437. .set_params = cx24113_set_params,
  438. .get_frequency = cx24113_get_frequency,
  439. .get_status = cx24113_get_status,
  440. };
  441. struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
  442. const struct cx24113_config *config, struct i2c_adapter *i2c)
  443. {
  444. /* allocate memory for the internal state */
  445. struct cx24113_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
  446. int rc;
  447. if (!state)
  448. return NULL;
  449. /* setup the state */
  450. state->config = config;
  451. state->i2c = i2c;
  452. cx_info("trying to detect myself\n");
  453. /* making a dummy read, because of some expected troubles
  454. * after power on */
  455. cx24113_readreg(state, 0x00);
  456. rc = cx24113_readreg(state, 0x00);
  457. if (rc < 0) {
  458. cx_info("CX24113 not found.\n");
  459. goto error;
  460. }
  461. state->rev = rc;
  462. switch (rc) {
  463. case 0x43:
  464. cx_info("detected CX24113 variant\n");
  465. break;
  466. case REV_CX24113:
  467. cx_info("successfully detected\n");
  468. break;
  469. default:
  470. cx_err("unsupported device id: %x\n", state->rev);
  471. goto error;
  472. }
  473. state->ver = cx24113_readreg(state, 0x01);
  474. cx_info("version: %x\n", state->ver);
  475. /* create dvb_frontend */
  476. memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
  477. sizeof(struct dvb_tuner_ops));
  478. fe->tuner_priv = state;
  479. return fe;
  480. error:
  481. kfree(state);
  482. return NULL;
  483. }
  484. EXPORT_SYMBOL(cx24113_attach);
  485. module_param(debug, int, 0644);
  486. MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
  487. MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
  488. MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
  489. MODULE_LICENSE("GPL");