htm9aw125_tuner.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * Xuguang htm-9a-w125 Tuner Device Driver
  3. *
  4. * Author: Bobby Yang <bo.yang@amlogic.com>
  5. *
  6. *
  7. * Copyright (C) 2010 Amlogic Inc.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. /* Standard Liniux Headers */
  14. #include <linux/module.h>
  15. #include <linux/i2c.h>
  16. /* Amlogic Headers */
  17. #include <linux/tvin/tvin.h>
  18. /* Local Headers */
  19. #include "tvin_tuner.h"
  20. #define HTM_TUNER_I2C_NAME "htm9aw125_tuner_i2c"
  21. #define TUNER_DEVICE_NAME "htm9aw125"
  22. /* tv tuner system standard selection for Xuguang htm-9a-w125
  23. this value takes the low bits of control byte 2
  24. standard BG DK I NTSC-M
  25. picture carrier 38.90 38.90 38.90 38.90
  26. colour 33.4 32.4 32.9 34.4
  27. */
  28. #define HTM_CB_SET_PAL_I 0xCE
  29. #define HTM_CB_SET_PAL_BGDK 0xCE
  30. #define HTM_CB_SET_NTSC_M 0xCE
  31. #define HTM_TUNER_FL 0x40
  32. #define HTM_FREQ_HIGH 426250000
  33. #define HTM_FREQ_LOW 143250000
  34. #define HTM_STEP_SIZE_0 50000
  35. #define HTM_STEP_SIZE_1 31250
  36. #define HTM_STEP_SIZE_3 62500
  37. typedef struct tuner_htm_s {
  38. tuner_std_id std_id;
  39. struct tuner_freq_s freq;
  40. struct tuner_parm_s parm;
  41. } tuner_fq1216me_t;
  42. static struct tuner_htm_s tuner_htm = {
  43. TUNER_STD_PAL_BG | TUNER_STD_PAL_DK |
  44. TUNER_STD_PAL_I |TUNER_STD_NTSC_M, //tuner_std_id std_id;
  45. {48250000, 0}, //u32 frequency;
  46. {48250000, 855250000, 0, 0, 0}, //struct tuner_parm_s parm;
  47. };
  48. static int htm_std_setup(u8 *cb, u32 *step_size)
  49. {
  50. /* tv norm specific stuff for multi-norm tuners */
  51. *cb = 0x0;
  52. if (tuner_htm.std_id & (TUNER_STD_PAL_BG|TUNER_STD_PAL_DK))
  53. {
  54. *cb |= HTM_CB_SET_PAL_BGDK; //(bit0)os == 0, normal mode
  55. //(bit[5:3])T == 0, normal mode
  56. //(bit[6])CP == 0, (charge pump current)fast tuning
  57. *step_size = HTM_STEP_SIZE_3; //base on the(bit[2:1] of cb) RAS & RSB, set the step size
  58. }
  59. else if (tuner_htm.std_id & TUNER_STD_PAL_I)
  60. {
  61. *cb |= HTM_CB_SET_PAL_I; //(bit0)os == 1, switch off the pll amplifier
  62. //(bit[5:3])T == 0, normal mode
  63. //(bit[6])CP == 1, (charge pump current) moderate tuning with slight better residual oscillator
  64. *step_size = HTM_STEP_SIZE_3; //TUNER_STEP_SIZE_0; //base on the(bit[2:1] of cb) RAS & RSB, set the step size
  65. }
  66. else if (tuner_htm.std_id & TUNER_STD_NTSC_M)
  67. {
  68. *cb |= HTM_CB_SET_NTSC_M; //(bit0)os == 1, switch off the pll amplifier
  69. //(bit[5:3])T == 0, normal mode
  70. //(bit[6])CP == 1, (charge pump current) moderate tuning with slight better residual oscillator
  71. *step_size = HTM_STEP_SIZE_3; //base on the(bit[2:1] of cb) RAS & RSB, set the step size
  72. }
  73. return 0;
  74. }
  75. static struct i2c_client *tuner_client = NULL;
  76. static int htm_tuner_read(char *buf, int len)
  77. {
  78. int i2c_flag = -1;
  79. int i = 0;
  80. unsigned int i2c_try_cnt = I2C_TRY_MAX_CNT;
  81. struct i2c_msg msg[] = {
  82. {
  83. .addr = tuner_client->addr,
  84. .flags = I2C_M_RD,
  85. .len = len,
  86. .buf = buf,
  87. },
  88. };
  89. repeat:
  90. i2c_flag = i2c_transfer(tuner_client->adapter, msg, 1);
  91. if (i2c_flag < 0) {
  92. pr_info("error in read htm_tuner, %d byte(s) should be read,. \n", len);
  93. if (i++ < i2c_try_cnt)
  94. goto repeat;
  95. return -EIO;
  96. }
  97. else
  98. {
  99. //pr_info("htm_tuner_read is ok. \n");
  100. return 0;
  101. }
  102. }
  103. static int htm_tuner_write(char *buf, int len)
  104. {
  105. int i2c_flag = -1;
  106. int i = 0;
  107. unsigned int i2c_try_cnt = I2C_TRY_MAX_CNT;
  108. struct i2c_msg msg[] = {
  109. {
  110. .addr = tuner_client->addr,
  111. .flags = 0, //|I2C_M_TEN,
  112. .len = len,
  113. .buf = buf,
  114. }
  115. };
  116. repeat:
  117. i2c_flag = i2c_transfer(tuner_client->adapter, msg, 1);
  118. if (i2c_flag < 0) {
  119. pr_info("error in writing htm_tuner, %d byte(s) should be writen,. \n", len);
  120. if (i++ < i2c_try_cnt)
  121. goto repeat;
  122. return -EIO;
  123. }
  124. else
  125. {
  126. //pr_info("htm_tuner_write is ok. \n");
  127. return 0;
  128. }
  129. }
  130. /* ---------------------------------------------------------------------- */
  131. static enum tuner_signal_status_e tuner_islocked(void)
  132. {
  133. unsigned char status = 0;
  134. htm_tuner_read(&status, 1);
  135. if ((status & HTM_TUNER_FL) != 0)
  136. return TUNER_SIGNAL_STATUS_STRONG;
  137. else
  138. return TUNER_SIGNAL_STATUS_WEAK;
  139. }
  140. /* ---------------------------------------------------------------------- */
  141. int tvin_set_tuner(void)
  142. {
  143. u8 buffer[5] = {0};
  144. u8 ab, cb, bb;
  145. u32 div, step_size = 0;
  146. unsigned int f_if;
  147. int i2c_flag;
  148. /* IFPCoff = Video Intermediate Frequency - Vif:
  149. 940 =16*58.75 NTSC/J (Japan)
  150. 732 =16*45.75 M/N STD
  151. 622.4=16*38.90 B/G D/K I, L STD
  152. 592 =16*37.00 D China
  153. 590 =16.36.875 B Australia
  154. 171.2=16*10.70 FM Radio (at set_radio_freq)
  155. */
  156. f_if = 38900000;
  157. if (tuner_htm.freq.freq < HTM_FREQ_LOW)
  158. bb = 0x01; //low band
  159. else if (tuner_htm.freq.freq > HTM_FREQ_HIGH)
  160. bb = 0x08; //high band
  161. else
  162. bb = 0x02; //mid band
  163. //tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
  164. // "Offset=%d.%02d MHz, div=%0d\n",
  165. // params->frequency / 16, params->frequency % 16 * 100 / 16,
  166. // IFPCoff / 16, IFPCoff % 16 * 100 / 16,
  167. // offset / 16, offset % 16 * 100 / 16, div);
  168. /* tv norm specific stuff for multi-norm tuners */
  169. htm_std_setup(&cb, &step_size);
  170. if (step_size > 0)
  171. div = (tuner_htm.freq.freq + f_if)/step_size; //with 62.5Khz step
  172. else
  173. div = (tuner_htm.freq.freq + f_if)/HTM_STEP_SIZE_0; //with 50Khz step
  174. ab = 0x60; //external AGC
  175. buffer[0] = (div >> 8) & 0xff;
  176. buffer[1] = div & 0xff;
  177. buffer[2] = cb;
  178. buffer[3] = bb;
  179. i2c_flag = htm_tuner_write(buffer, 4);
  180. return i2c_flag;
  181. }
  182. char *tvin_tuenr_get_name(void)
  183. {
  184. return TUNER_DEVICE_NAME;
  185. }
  186. void tvin_get_tuner( struct tuner_parm_s *ptp)
  187. {
  188. ptp->rangehigh = tuner_htm.parm.rangehigh;
  189. ptp->rangelow = tuner_htm.parm.rangelow;
  190. ptp->signal = tuner_islocked();
  191. }
  192. void tvin_tuner_get_std(tuner_std_id *ptstd)
  193. {
  194. *ptstd = tuner_htm.std_id;
  195. }
  196. void tvin_tuner_set_std(tuner_std_id ptstd)
  197. {
  198. tuner_htm.std_id = ptstd;
  199. }
  200. void tvin_tuner_get_freq(struct tuner_freq_s *ptf)
  201. {
  202. ptf->freq = tuner_htm.freq.freq;
  203. }
  204. void tvin_tuner_set_freq(struct tuner_freq_s tf)
  205. {
  206. tuner_htm.freq.freq = tf.freq;
  207. }
  208. static int htm_tuner_probe(struct i2c_client *client, const struct i2c_device_id *id)
  209. {
  210. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  211. pr_info("%s: functionality check failed\n", __FUNCTION__);
  212. return -ENODEV;
  213. }
  214. tuner_client = client;
  215. printk( "tuner_client->addr = %x\n", tuner_client->addr);
  216. return 0;
  217. }
  218. static int htm_tuner_remove(struct i2c_client *client)
  219. {
  220. pr_info("%s driver removed ok.\n", client->name);
  221. return 0;
  222. }
  223. static const struct i2c_device_id htm_tuner_id[] = {
  224. {HTM_TUNER_I2C_NAME, 0},
  225. { }
  226. };
  227. MODULE_DEVICE_TABLE(i2c, htm_tuner_id);
  228. static struct i2c_driver htm_tuner_driver = {
  229. .driver = {
  230. .owner = THIS_MODULE,
  231. .name = HTM_TUNER_I2C_NAME,
  232. },
  233. .probe = htm_tuner_probe,
  234. .remove = htm_tuner_remove,
  235. .id_table = htm_tuner_id,
  236. };
  237. static int __init htm_tuner_init(void)
  238. {
  239. int ret = 0;
  240. pr_info( "%s . \n", __FUNCTION__ );
  241. ret = i2c_add_driver(&htm_tuner_driver);
  242. if (ret < 0 || tuner_client == NULL) {
  243. pr_err("tuner: failed to add i2c driver. \n");
  244. ret = -ENOTSUPP;
  245. }
  246. return ret;
  247. }
  248. static void __exit htm_tuner_exit(void)
  249. {
  250. pr_info( "%s . \n", __FUNCTION__ );
  251. i2c_del_driver(&htm_tuner_driver);
  252. }
  253. MODULE_AUTHOR("Bobby Yang <bo.yang@amlogic.com>");
  254. MODULE_DESCRIPTION("Xuguang htm-9a-w125 tuner i2c device driver");
  255. MODULE_LICENSE("GPL");
  256. module_init(htm_tuner_init);
  257. module_exit(htm_tuner_exit);