mc44s803.c 8.9 KB

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