mc44s803.c 8.9 KB

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