tua6100.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Driver for Infineon tua6100 pll.
  4. *
  5. * (c) 2006 Andrew de Quincey
  6. *
  7. * Based on code found in budget-av.c, which has the following:
  8. * Compiled from various sources by Michael Hunold <michael@mihu.de>
  9. *
  10. * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
  11. * Andrew de Quincey <adq_dvb@lidskialf.net>
  12. *
  13. * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  14. *
  15. * Copyright (C) 1999-2002 Ralph Metzler
  16. * & Marcus Metzler for convergence integrated media GmbH
  17. */
  18. #include <linux/slab.h>
  19. #include <linux/module.h>
  20. #include <linux/dvb/frontend.h>
  21. #include <asm/types.h>
  22. #include "tua6100.h"
  23. struct tua6100_priv {
  24. /* i2c details */
  25. int i2c_address;
  26. struct i2c_adapter *i2c;
  27. u32 frequency;
  28. };
  29. static void tua6100_release(struct dvb_frontend *fe)
  30. {
  31. kfree(fe->tuner_priv);
  32. fe->tuner_priv = NULL;
  33. }
  34. static int tua6100_sleep(struct dvb_frontend *fe)
  35. {
  36. struct tua6100_priv *priv = fe->tuner_priv;
  37. int ret;
  38. u8 reg0[] = { 0x00, 0x00 };
  39. struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
  40. if (fe->ops.i2c_gate_ctrl)
  41. fe->ops.i2c_gate_ctrl(fe, 1);
  42. if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
  43. printk("%s: i2c error\n", __func__);
  44. }
  45. if (fe->ops.i2c_gate_ctrl)
  46. fe->ops.i2c_gate_ctrl(fe, 0);
  47. return (ret == 1) ? 0 : ret;
  48. }
  49. static int tua6100_set_params(struct dvb_frontend *fe)
  50. {
  51. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  52. struct tua6100_priv *priv = fe->tuner_priv;
  53. u32 div;
  54. u32 prediv;
  55. u8 reg0[] = { 0x00, 0x00 };
  56. u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
  57. u8 reg2[] = { 0x02, 0x00, 0x00 };
  58. struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
  59. struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
  60. struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
  61. #define _R_VAL 4
  62. #define _P_VAL 32
  63. #define _ri 4000000
  64. // setup register 0
  65. if (c->frequency < 2000000)
  66. reg0[1] = 0x03;
  67. else
  68. reg0[1] = 0x07;
  69. // setup register 1
  70. if (c->frequency < 1630000)
  71. reg1[1] = 0x2c;
  72. else
  73. reg1[1] = 0x0c;
  74. if (_P_VAL == 64)
  75. reg1[1] |= 0x40;
  76. if (c->frequency >= 1525000)
  77. reg1[1] |= 0x80;
  78. // register 2
  79. reg2[1] = (_R_VAL >> 8) & 0x03;
  80. reg2[2] = _R_VAL;
  81. if (c->frequency < 1455000)
  82. reg2[1] |= 0x1c;
  83. else if (c->frequency < 1630000)
  84. reg2[1] |= 0x0c;
  85. else
  86. reg2[1] |= 0x1c;
  87. /*
  88. * The N divisor ratio (note: c->frequency is in kHz, but we
  89. * need it in Hz)
  90. */
  91. prediv = (c->frequency * _R_VAL) / (_ri / 1000);
  92. div = prediv / _P_VAL;
  93. reg1[1] |= (div >> 9) & 0x03;
  94. reg1[2] = div >> 1;
  95. reg1[3] = (div << 7);
  96. priv->frequency = ((div * _P_VAL) * (_ri / 1000)) / _R_VAL;
  97. // Finally, calculate and store the value for A
  98. reg1[3] |= (prediv - (div*_P_VAL)) & 0x7f;
  99. #undef _R_VAL
  100. #undef _P_VAL
  101. #undef _ri
  102. if (fe->ops.i2c_gate_ctrl)
  103. fe->ops.i2c_gate_ctrl(fe, 1);
  104. if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
  105. return -EIO;
  106. if (fe->ops.i2c_gate_ctrl)
  107. fe->ops.i2c_gate_ctrl(fe, 1);
  108. if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
  109. return -EIO;
  110. if (fe->ops.i2c_gate_ctrl)
  111. fe->ops.i2c_gate_ctrl(fe, 1);
  112. if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
  113. return -EIO;
  114. if (fe->ops.i2c_gate_ctrl)
  115. fe->ops.i2c_gate_ctrl(fe, 0);
  116. return 0;
  117. }
  118. static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  119. {
  120. struct tua6100_priv *priv = fe->tuner_priv;
  121. *frequency = priv->frequency;
  122. return 0;
  123. }
  124. static const struct dvb_tuner_ops tua6100_tuner_ops = {
  125. .info = {
  126. .name = "Infineon TUA6100",
  127. .frequency_min_hz = 950 * MHz,
  128. .frequency_max_hz = 2150 * MHz,
  129. .frequency_step_hz = 1 * MHz,
  130. },
  131. .release = tua6100_release,
  132. .sleep = tua6100_sleep,
  133. .set_params = tua6100_set_params,
  134. .get_frequency = tua6100_get_frequency,
  135. };
  136. struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
  137. {
  138. struct tua6100_priv *priv = NULL;
  139. u8 b1 [] = { 0x80 };
  140. u8 b2 [] = { 0x00 };
  141. struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
  142. { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
  143. int ret;
  144. if (fe->ops.i2c_gate_ctrl)
  145. fe->ops.i2c_gate_ctrl(fe, 1);
  146. ret = i2c_transfer (i2c, msg, 2);
  147. if (fe->ops.i2c_gate_ctrl)
  148. fe->ops.i2c_gate_ctrl(fe, 0);
  149. if (ret != 2)
  150. return NULL;
  151. priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
  152. if (priv == NULL)
  153. return NULL;
  154. priv->i2c_address = addr;
  155. priv->i2c = i2c;
  156. memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
  157. fe->tuner_priv = priv;
  158. return fe;
  159. }
  160. EXPORT_SYMBOL(tua6100_attach);
  161. MODULE_DESCRIPTION("DVB tua6100 driver");
  162. MODULE_AUTHOR("Andrew de Quincey");
  163. MODULE_LICENSE("GPL");