mc44s803.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
  4. *
  5. * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/delay.h>
  9. #include <linux/dvb/frontend.h>
  10. #include <linux/i2c.h>
  11. #include <linux/slab.h>
  12. #include <media/dvb_frontend.h>
  13. #include "mc44s803.h"
  14. #include "mc44s803_priv.h"
  15. #define mc_printk(level, format, arg...) \
  16. printk(level "mc44s803: " format , ## arg)
  17. /* Writes a single register */
  18. static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
  19. {
  20. u8 buf[3];
  21. struct i2c_msg msg = {
  22. .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
  23. };
  24. buf[0] = (val & 0xff0000) >> 16;
  25. buf[1] = (val & 0xff00) >> 8;
  26. buf[2] = (val & 0xff);
  27. if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
  28. mc_printk(KERN_WARNING, "I2C write failed\n");
  29. return -EREMOTEIO;
  30. }
  31. return 0;
  32. }
  33. /* Reads a single register */
  34. static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
  35. {
  36. u32 wval;
  37. u8 buf[3];
  38. int ret;
  39. struct i2c_msg msg[] = {
  40. { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
  41. .buf = buf, .len = 3 },
  42. };
  43. wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
  44. MC44S803_REG_SM(reg, MC44S803_D);
  45. ret = mc44s803_writereg(priv, wval);
  46. if (ret)
  47. return ret;
  48. if (i2c_transfer(priv->i2c, msg, 1) != 1) {
  49. mc_printk(KERN_WARNING, "I2C read failed\n");
  50. return -EREMOTEIO;
  51. }
  52. *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
  53. return 0;
  54. }
  55. static void mc44s803_release(struct dvb_frontend *fe)
  56. {
  57. struct mc44s803_priv *priv = fe->tuner_priv;
  58. fe->tuner_priv = NULL;
  59. kfree(priv);
  60. }
  61. static int mc44s803_init(struct dvb_frontend *fe)
  62. {
  63. struct mc44s803_priv *priv = fe->tuner_priv;
  64. u32 val;
  65. int err;
  66. if (fe->ops.i2c_gate_ctrl)
  67. fe->ops.i2c_gate_ctrl(fe, 1);
  68. /* Reset chip */
  69. val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
  70. MC44S803_REG_SM(1, MC44S803_RS);
  71. err = mc44s803_writereg(priv, val);
  72. if (err)
  73. goto exit;
  74. val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
  75. err = mc44s803_writereg(priv, val);
  76. if (err)
  77. goto exit;
  78. /* Power Up and Start Osc */
  79. val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
  80. MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
  81. MC44S803_REG_SM(1, MC44S803_OSCSEL);
  82. err = mc44s803_writereg(priv, val);
  83. if (err)
  84. goto exit;
  85. val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
  86. MC44S803_REG_SM(0x200, MC44S803_POWER);
  87. err = mc44s803_writereg(priv, val);
  88. if (err)
  89. goto exit;
  90. msleep(10);
  91. val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
  92. MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
  93. MC44S803_REG_SM(1, MC44S803_OSCSEL);
  94. err = mc44s803_writereg(priv, val);
  95. if (err)
  96. goto exit;
  97. msleep(20);
  98. /* Setup Mixer */
  99. val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
  100. MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
  101. MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
  102. err = mc44s803_writereg(priv, val);
  103. if (err)
  104. goto exit;
  105. /* Setup Cirquit Adjust */
  106. val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
  107. MC44S803_REG_SM(1, MC44S803_G1) |
  108. MC44S803_REG_SM(1, MC44S803_G3) |
  109. MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
  110. MC44S803_REG_SM(1, MC44S803_G6) |
  111. MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
  112. MC44S803_REG_SM(0x3, MC44S803_LP) |
  113. MC44S803_REG_SM(1, MC44S803_CLRF) |
  114. MC44S803_REG_SM(1, MC44S803_CLIF);
  115. err = mc44s803_writereg(priv, val);
  116. if (err)
  117. goto exit;
  118. val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
  119. MC44S803_REG_SM(1, MC44S803_G1) |
  120. MC44S803_REG_SM(1, MC44S803_G3) |
  121. MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
  122. MC44S803_REG_SM(1, MC44S803_G6) |
  123. MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
  124. MC44S803_REG_SM(0x3, MC44S803_LP);
  125. err = mc44s803_writereg(priv, val);
  126. if (err)
  127. goto exit;
  128. /* Setup Digtune */
  129. val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
  130. MC44S803_REG_SM(3, MC44S803_XOD);
  131. err = mc44s803_writereg(priv, val);
  132. if (err)
  133. goto exit;
  134. /* Setup AGC */
  135. val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
  136. MC44S803_REG_SM(1, MC44S803_AT1) |
  137. MC44S803_REG_SM(1, MC44S803_AT2) |
  138. MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
  139. MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
  140. MC44S803_REG_SM(1, MC44S803_LNA0);
  141. err = mc44s803_writereg(priv, val);
  142. if (err)
  143. goto exit;
  144. if (fe->ops.i2c_gate_ctrl)
  145. fe->ops.i2c_gate_ctrl(fe, 0);
  146. return 0;
  147. exit:
  148. if (fe->ops.i2c_gate_ctrl)
  149. fe->ops.i2c_gate_ctrl(fe, 0);
  150. mc_printk(KERN_WARNING, "I/O Error\n");
  151. return err;
  152. }
  153. static int mc44s803_set_params(struct dvb_frontend *fe)
  154. {
  155. struct mc44s803_priv *priv = fe->tuner_priv;
  156. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  157. u32 r1, r2, n1, n2, lo1, lo2, freq, val;
  158. int err;
  159. priv->frequency = c->frequency;
  160. r1 = MC44S803_OSC / 1000000;
  161. r2 = MC44S803_OSC / 100000;
  162. n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
  163. freq = MC44S803_OSC / r1 * n1;
  164. lo1 = ((60 * n1) + (r1 / 2)) / r1;
  165. freq = freq - c->frequency;
  166. n2 = (freq - MC44S803_IF2 + 50000) / 100000;
  167. lo2 = ((60 * n2) + (r2 / 2)) / r2;
  168. if (fe->ops.i2c_gate_ctrl)
  169. fe->ops.i2c_gate_ctrl(fe, 1);
  170. val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
  171. MC44S803_REG_SM(r1-1, MC44S803_R1) |
  172. MC44S803_REG_SM(r2-1, MC44S803_R2) |
  173. MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
  174. err = mc44s803_writereg(priv, val);
  175. if (err)
  176. goto exit;
  177. val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
  178. MC44S803_REG_SM(n1-2, MC44S803_LO1);
  179. err = mc44s803_writereg(priv, val);
  180. if (err)
  181. goto exit;
  182. val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
  183. MC44S803_REG_SM(n2-2, MC44S803_LO2);
  184. err = mc44s803_writereg(priv, val);
  185. if (err)
  186. goto exit;
  187. val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
  188. MC44S803_REG_SM(1, MC44S803_DA) |
  189. MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
  190. MC44S803_REG_SM(1, MC44S803_AT);
  191. err = mc44s803_writereg(priv, val);
  192. if (err)
  193. goto exit;
  194. val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
  195. MC44S803_REG_SM(2, MC44S803_DA) |
  196. MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
  197. MC44S803_REG_SM(1, MC44S803_AT);
  198. err = mc44s803_writereg(priv, val);
  199. if (err)
  200. goto exit;
  201. if (fe->ops.i2c_gate_ctrl)
  202. fe->ops.i2c_gate_ctrl(fe, 0);
  203. return 0;
  204. exit:
  205. if (fe->ops.i2c_gate_ctrl)
  206. fe->ops.i2c_gate_ctrl(fe, 0);
  207. mc_printk(KERN_WARNING, "I/O Error\n");
  208. return err;
  209. }
  210. static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  211. {
  212. struct mc44s803_priv *priv = fe->tuner_priv;
  213. *frequency = priv->frequency;
  214. return 0;
  215. }
  216. static int mc44s803_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
  217. {
  218. *frequency = MC44S803_IF2; /* 36.125 MHz */
  219. return 0;
  220. }
  221. static const struct dvb_tuner_ops mc44s803_tuner_ops = {
  222. .info = {
  223. .name = "Freescale MC44S803",
  224. .frequency_min_hz = 48 * MHz,
  225. .frequency_max_hz = 1000 * MHz,
  226. .frequency_step_hz = 100 * kHz,
  227. },
  228. .release = mc44s803_release,
  229. .init = mc44s803_init,
  230. .set_params = mc44s803_set_params,
  231. .get_frequency = mc44s803_get_frequency,
  232. .get_if_frequency = mc44s803_get_if_frequency,
  233. };
  234. /* This functions tries to identify a MC44S803 tuner by reading the ID
  235. register. This is hasty. */
  236. struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
  237. struct i2c_adapter *i2c, struct mc44s803_config *cfg)
  238. {
  239. struct mc44s803_priv *priv;
  240. u32 reg;
  241. u8 id;
  242. int ret;
  243. reg = 0;
  244. priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
  245. if (priv == NULL)
  246. return NULL;
  247. priv->cfg = cfg;
  248. priv->i2c = i2c;
  249. priv->fe = fe;
  250. if (fe->ops.i2c_gate_ctrl)
  251. fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
  252. ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
  253. if (ret)
  254. goto error;
  255. id = MC44S803_REG_MS(reg, MC44S803_ID);
  256. if (id != 0x14) {
  257. mc_printk(KERN_ERR, "unsupported ID (%x should be 0x14)\n",
  258. id);
  259. goto error;
  260. }
  261. mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
  262. memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
  263. sizeof(struct dvb_tuner_ops));
  264. fe->tuner_priv = priv;
  265. if (fe->ops.i2c_gate_ctrl)
  266. fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
  267. return fe;
  268. error:
  269. if (fe->ops.i2c_gate_ctrl)
  270. fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
  271. kfree(priv);
  272. return NULL;
  273. }
  274. EXPORT_SYMBOL(mc44s803_attach);
  275. MODULE_AUTHOR("Jochen Friedrich");
  276. MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
  277. MODULE_LICENSE("GPL");