mc44s803.c 9.1 KB

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