tda665x.c 5.3 KB

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