tda665x.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. TDA665x tuner driver
  3. Copyright (C) Manu Abraham (abraham.manu@gmail.com)
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <linux/init.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/slab.h>
  20. #include "dvb_frontend.h"
  21. #include "tda665x.h"
  22. struct tda665x_state {
  23. struct dvb_frontend *fe;
  24. struct i2c_adapter *i2c;
  25. const struct tda665x_config *config;
  26. u32 frequency;
  27. u32 bandwidth;
  28. };
  29. static int tda665x_read(struct tda665x_state *state, u8 *buf)
  30. {
  31. const struct tda665x_config *config = state->config;
  32. int err = 0;
  33. struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
  34. err = i2c_transfer(state->i2c, &msg, 1);
  35. if (err != 1)
  36. goto exit;
  37. return err;
  38. exit:
  39. printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
  40. return err;
  41. }
  42. static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
  43. {
  44. const struct tda665x_config *config = state->config;
  45. int err = 0;
  46. struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
  47. err = i2c_transfer(state->i2c, &msg, 1);
  48. if (err != 1)
  49. goto exit;
  50. return err;
  51. exit:
  52. printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
  53. return err;
  54. }
  55. static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
  56. {
  57. struct tda665x_state *state = fe->tuner_priv;
  58. *frequency = state->frequency;
  59. return 0;
  60. }
  61. static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
  62. {
  63. struct tda665x_state *state = fe->tuner_priv;
  64. u8 result = 0;
  65. int err = 0;
  66. *status = 0;
  67. err = tda665x_read(state, &result);
  68. if (err < 0)
  69. goto exit;
  70. if ((result >> 6) & 0x01) {
  71. printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
  72. *status = 1;
  73. }
  74. return err;
  75. exit:
  76. printk(KERN_ERR "%s: I/O Error\n", __func__);
  77. return err;
  78. }
  79. static int tda665x_set_frequency(struct dvb_frontend *fe,
  80. u32 new_frequency)
  81. {
  82. struct tda665x_state *state = fe->tuner_priv;
  83. const struct tda665x_config *config = state->config;
  84. u32 frequency, status = 0;
  85. u8 buf[4];
  86. int err = 0;
  87. if ((new_frequency < config->frequency_max)
  88. || (new_frequency > config->frequency_min)) {
  89. printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
  90. __func__, new_frequency);
  91. return -EINVAL;
  92. }
  93. frequency = new_frequency;
  94. frequency += config->frequency_offst;
  95. frequency *= config->ref_multiplier;
  96. frequency += config->ref_divider >> 1;
  97. frequency /= config->ref_divider;
  98. buf[0] = (u8) ((frequency & 0x7f00) >> 8);
  99. buf[1] = (u8) (frequency & 0x00ff) >> 0;
  100. buf[2] = 0x80 | 0x40 | 0x02;
  101. buf[3] = 0x00;
  102. /* restore frequency */
  103. frequency = new_frequency;
  104. if (frequency < 153000000) {
  105. /* VHF-L */
  106. buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
  107. if (frequency < 68000000)
  108. buf[3] |= 0x40; /* 83uA */
  109. if (frequency < 1040000000)
  110. buf[3] |= 0x60; /* 122uA */
  111. if (frequency < 1250000000)
  112. buf[3] |= 0x80; /* 163uA */
  113. else
  114. buf[3] |= 0xa0; /* 254uA */
  115. } else if (frequency < 438000000) {
  116. /* VHF-H */
  117. buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
  118. if (frequency < 230000000)
  119. buf[3] |= 0x40;
  120. if (frequency < 300000000)
  121. buf[3] |= 0x60;
  122. else
  123. buf[3] |= 0x80;
  124. } else {
  125. /* UHF */
  126. buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
  127. if (frequency < 470000000)
  128. buf[3] |= 0x60;
  129. if (frequency < 526000000)
  130. buf[3] |= 0x80;
  131. else
  132. buf[3] |= 0xa0;
  133. }
  134. /* Set params */
  135. err = tda665x_write(state, buf, 5);
  136. if (err < 0)
  137. goto exit;
  138. /* sleep for some time */
  139. printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
  140. msleep(20);
  141. /* check status */
  142. err = tda665x_get_status(fe, &status);
  143. if (err < 0)
  144. goto exit;
  145. if (status == 1) {
  146. printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
  147. __func__, status);
  148. state->frequency = frequency; /* cache successful state */
  149. } else {
  150. printk(KERN_ERR "%s: No Phase lock: status=%d\n",
  151. __func__, status);
  152. }
  153. return 0;
  154. exit:
  155. printk(KERN_ERR "%s: I/O Error\n", __func__);
  156. return err;
  157. }
  158. static int tda665x_set_params(struct dvb_frontend *fe)
  159. {
  160. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  161. tda665x_set_frequency(fe, c->frequency);
  162. return 0;
  163. }
  164. static int tda665x_release(struct dvb_frontend *fe)
  165. {
  166. struct tda665x_state *state = fe->tuner_priv;
  167. fe->tuner_priv = NULL;
  168. kfree(state);
  169. return 0;
  170. }
  171. static const struct dvb_tuner_ops tda665x_ops = {
  172. .get_status = tda665x_get_status,
  173. .set_params = tda665x_set_params,
  174. .get_frequency = tda665x_get_frequency,
  175. .release = tda665x_release
  176. };
  177. struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
  178. const struct tda665x_config *config,
  179. struct i2c_adapter *i2c)
  180. {
  181. struct tda665x_state *state = NULL;
  182. struct dvb_tuner_info *info;
  183. state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
  184. if (!state)
  185. return NULL;
  186. state->config = config;
  187. state->i2c = i2c;
  188. state->fe = fe;
  189. fe->tuner_priv = state;
  190. fe->ops.tuner_ops = tda665x_ops;
  191. info = &fe->ops.tuner_ops.info;
  192. memcpy(info->name, config->name, sizeof(config->name));
  193. info->frequency_min = config->frequency_min;
  194. info->frequency_max = config->frequency_max;
  195. info->frequency_step = config->frequency_offst;
  196. printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
  197. return fe;
  198. }
  199. EXPORT_SYMBOL(tda665x_attach);
  200. MODULE_DESCRIPTION("TDA665x driver");
  201. MODULE_AUTHOR("Manu Abraham");
  202. MODULE_LICENSE("GPL");