si2176_tuner.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * Silicon labs si2176 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. #include <linux/delay.h>
  17. /* Amlogic Headers */
  18. #include <linux/tvin/tvin.h>
  19. /* Local Headers */
  20. #include "tvin_tuner.h"
  21. #include "tvin_demod.h"
  22. #include "si2176_func.h"
  23. #define SI2176_TUNER_I2C_NAME "si2176_tuner_i2c"
  24. #define TUNER_DEVICE_NAME "si2176"
  25. static struct i2c_client *tuner_client = NULL;
  26. static si2176_common_reply_struct si_common_reply;
  27. static si2176_propobj_t si_prop;
  28. static si2176_cmdreplyobj_t si_cmd_reply;
  29. static tuner_std_id si_std_id = 0;
  30. /************************************************************************************************************************/
  31. /** globals for Top Level routine */
  32. unsigned int newfrequency;
  33. /* ---------------------------------------------------------------------- */
  34. static enum tuner_signal_status_e si2176_tuner_islocked(void)
  35. {
  36. enum tuner_signal_status_e ret = TUNER_SIGNAL_STATUS_WEAK;
  37. #if 0
  38. if (si_common_reply.tunint && si_common_reply.atvint)
  39. {
  40. pr_info("%s: Strong signal detected...tunint:%d.atvint:%d.....\n", __func__,
  41. si_common_reply.tunint,
  42. si_common_reply.atvint);
  43. ret = TUNER_SIGNAL_STATUS_STRONG;
  44. }
  45. else
  46. pr_info("%s: Weak signal detected.........\n", __func__);
  47. #else
  48. si2176_tuner_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply);
  49. #if 0
  50. if (!si_cmd_reply.tuner_status.status->atvint || !si_cmd_reply.tuner_status.status->tunint)
  51. {
  52. pr_info("%s: tuner unstable atvint:%d tunint:%d............\n", __func__,
  53. si_cmd_reply.tuner_status.status->atvint,
  54. si_cmd_reply.tuner_status.status->tunint);
  55. return ret;
  56. }
  57. #endif
  58. if (!si_cmd_reply.tuner_status.rssih && !si_cmd_reply.tuner_status.rssil)
  59. {
  60. if(SI2176_DEBUG)
  61. pr_info("%s: Strong signal detected.........\n", __func__);
  62. ret = TUNER_SIGNAL_STATUS_STRONG;
  63. }
  64. else{
  65. if(SI2176_DEBUG)
  66. pr_info("%s: Weak signal rssih:%d rssil:%d............\n", __func__,
  67. si_cmd_reply.tuner_status.rssih,
  68. si_cmd_reply.tuner_status.rssil);
  69. }
  70. #endif
  71. return ret;
  72. }
  73. /* ---------------------------------------------------------------------- */
  74. int tvin_set_tuner(void)
  75. {
  76. int ret = 0;
  77. #if 0
  78. si2176_tuner_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply);
  79. si2176_atv_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply);
  80. pr_info("...range_khz:%d, \n...atv_cvbs_out.amp:%d,\n...offset:%d,\n...atv_cvbs_out_fine.amp:%d,\n...offset:%d,\n...atv_min_lvl_lock.thrs:%d,\n...atv_rf_top.atv_rf_top:%d,\n...atv_rsq_rssi_threshold.hi:%d, \n...atv_rsq_rssi_threshold.lo:%d,\n...atv_rsq_rssi_threshold.hi:%d,\n...atv_rsq_rssi_threshold.lo:%d,\n...atv_rsq_snr_threshold.hi:%d,\n...atv_rsq_snr_threshold.lo:%d,\n...atv_video_equalizer.slope:%d,\n...atv_video_mode.color:%d,\n...atv_video_mode.invert_signal:%d,\n...atv_video_mode.trans:%d,\n...atv_video_mode.video_sys:%d,\n...atv_vsnr_cap.atv_vsnr_cap:%d,\n...atv_vsync_tracking.min_fields_to_unlock:%d,\n...atv_vsync_tracking.min_pulses_to_lock:%d,\n...tuner_blocked_vco.vco_code:%d \n",
  81. si_prop.atv_afc_range.range_khz,
  82. si_prop.atv_cvbs_out.amp,
  83. si_prop.atv_cvbs_out.offset,
  84. si_prop.atv_cvbs_out_fine.amp,
  85. si_prop.atv_cvbs_out_fine.offset,
  86. si_prop.atv_min_lvl_lock.thrs,
  87. si_prop.atv_rf_top.atv_rf_top,
  88. si_prop.atv_rsq_rssi_threshold.hi,
  89. si_prop.atv_rsq_rssi_threshold.lo,
  90. si_prop.atv_rsq_rssi_threshold.hi,
  91. si_prop.atv_rsq_rssi_threshold.lo,
  92. si_prop.atv_rsq_snr_threshold.hi,
  93. si_prop.atv_rsq_snr_threshold.lo,
  94. si_prop.atv_video_equalizer.slope,
  95. si_prop.atv_video_mode.color,
  96. si_prop.atv_video_mode.invert_signal,
  97. si_prop.atv_video_mode.trans,
  98. si_prop.atv_video_mode.video_sys,
  99. si_prop.atv_vsnr_cap.atv_vsnr_cap,
  100. si_prop.atv_vsync_tracking.min_fields_to_unlock,
  101. si_prop.atv_vsync_tracking.min_pulses_to_lock,
  102. si_prop.tuner_blocked_vco.vco_code);
  103. pr_info("...atv_status.chlint:%d, \n...atv_status.pclint:%d, \n...atv_status.dlint:%d, \n...atv_status.snrlint:%d, \n...atv_status.snrhint:%d, \n...atv_status.chl:%d, \n...atv_status.pcl:%d, \n...atv_status.dl:%d, \n...atv_status.snrl:%d, \n...atv_status.snrh:%d, \n...atv_status.video_snr:%d, \n...atv_status.afc_freq:%d, \n...atv_status.video_sc_spacing:%d, \n...atv_status.video_sys:%d, \n...atv_status.color:%d, \n...atv_status.trans:%d, \n...tuner_status.vco_code:%d, \n...tuner_status.tc:%d, \n...tuner_status.rssil:%d, \n...tuner_status.rssih:%d, \n...tuner_status.rssi:%d, \n...tuner_status.freq:%d, \n...tuner_status.mode:%d \n",
  104. si_cmd_reply.atv_status.chlint,
  105. si_cmd_reply.atv_status.pclint,
  106. si_cmd_reply.atv_status.dlint,
  107. si_cmd_reply.atv_status.snrlint,
  108. si_cmd_reply.atv_status.snrhint,
  109. si_cmd_reply.atv_status.chl,
  110. si_cmd_reply.atv_status.pcl,
  111. si_cmd_reply.atv_status.dl,
  112. si_cmd_reply.atv_status.snrl,
  113. si_cmd_reply.atv_status.snrh,
  114. si_cmd_reply.atv_status.video_snr,
  115. si_cmd_reply.atv_status.afc_freq,
  116. si_cmd_reply.atv_status.video_sc_spacing,
  117. si_cmd_reply.atv_status.video_sys,
  118. si_cmd_reply.atv_status.color,
  119. si_cmd_reply.atv_status.trans,
  120. si_cmd_reply.tuner_status.vco_code,
  121. si_cmd_reply.tuner_status.tc,
  122. si_cmd_reply.tuner_status.rssil,
  123. si_cmd_reply.tuner_status.rssih,
  124. si_cmd_reply.tuner_status.rssi,
  125. si_cmd_reply.tuner_status.freq,
  126. si_cmd_reply.tuner_status.mode);
  127. pr_info("...common_reply.atvint:%d, \n...common_reply.cts:%d, \n...common_reply.err:%d, \n...common_reply.tunint:%d, \n",
  128. si_common_reply.atvint,
  129. si_common_reply.cts,
  130. si_common_reply.err,
  131. si_common_reply.tunint);
  132. #endif
  133. return ret;
  134. }
  135. char *tvin_tuenr_get_name(void)
  136. {
  137. return TUNER_DEVICE_NAME;
  138. }
  139. void tvin_get_tuner( struct tuner_parm_s *ptp)
  140. {
  141. ptp->rangehigh = 48250000;
  142. ptp->rangelow = 855250000;
  143. ptp->signal = si2176_tuner_islocked();
  144. }
  145. void tvin_tuner_get_std(tuner_std_id *ptstd)
  146. {
  147. *ptstd = si_std_id;
  148. }
  149. void tvin_tuner_set_std(tuner_std_id ptstd)
  150. {
  151. si_std_id = ptstd;
  152. if (si_std_id & (TUNER_STD_PAL | TUNER_STD_NTSC))
  153. {
  154. si_prop.atv_video_mode.color = SI2176_ATV_VIDEO_MODE_PROP_COLOR_PAL_NTSC;
  155. }
  156. else if (si_std_id & (TUNER_STD_SECAM))
  157. {
  158. si_prop.atv_video_mode.color = SI2176_ATV_VIDEO_MODE_PROP_COLOR_SECAM;
  159. }
  160. if(SI2176_DEBUG)
  161. pr_info("%s: atv_video_mode.color:%d \n", __func__, si_prop.atv_video_mode.color);
  162. }
  163. void tvin_tuner_get_freq(struct tuner_freq_s *ptf)
  164. {
  165. ptf->freq = newfrequency;
  166. }
  167. void tvin_tuner_set_freq(struct tuner_freq_s tf)
  168. {
  169. newfrequency = tf.freq;
  170. if(SI2176_DEBUG)
  171. pr_info("%s: ptf->freq:%d \n", __func__, tf.freq);
  172. }
  173. int tvin_set_demod(unsigned int bce)
  174. {
  175. int ret = 0;
  176. ret = si2176_tune(tuner_client, SI2176_TUNER_TUNE_FREQ_CMD_MODE_ATV, newfrequency, &si_cmd_reply, &si_common_reply);
  177. if (ret)
  178. pr_info("%s: atv tune error:%d!!!!\n", __func__, ret);
  179. return ret;
  180. }
  181. void tvin_demod_set_std(tuner_std_id ptstd)
  182. {
  183. si_std_id = ptstd;
  184. //audio mute judge
  185. if (si_std_id == 0) {
  186. si_prop.atv_af_out.volume = 0;
  187. if (SI2176_DEBUG) {
  188. pr_info("si2176 audio mute on, si_std_id = %d.\n", si_std_id);
  189. }
  190. } else {
  191. si_prop.atv_af_out.volume = SI2176_ATV_AF_OUT_PROP_VOLUME_VOLUME_MAX;
  192. if (SI2176_DEBUG) {
  193. pr_info("si2176 audio mute off, si_std_id = %d.\n", si_std_id);
  194. }
  195. }
  196. if (si_std_id & TUNER_STD_PAL_B)
  197. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_B;
  198. else if (si_std_id & (TUNER_STD_PAL_G | TUNER_STD_PAL_H))
  199. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_GH;
  200. else if (si_std_id & (TUNER_STD_PAL_M |
  201. TUNER_STD_NTSC_M |
  202. TUNER_STD_NTSC_M_JP))
  203. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_M;
  204. else if (si_std_id & TUNER_STD_PAL_N)
  205. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_N;
  206. else if (si_std_id & TUNER_STD_PAL_I)
  207. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_I;
  208. else if (si_std_id & (TUNER_STD_PAL_D |
  209. TUNER_STD_PAL_D1 |
  210. TUNER_STD_PAL_DK))
  211. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_DK;
  212. else if (si_std_id & TUNER_STD_SECAM_L)
  213. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_L;
  214. else if (si_std_id & TUNER_STD_SECAM_LC)
  215. si_prop.atv_video_mode.video_sys = SI2176_ATV_VIDEO_MODE_PROP_VIDEO_SYS_LP;
  216. if (si2176_atvconfig(tuner_client, &si_prop, &si_cmd_reply)!=0)
  217. {
  218. if(SI2176_DEBUG)
  219. pr_info("%s:set std error\n",__func__);
  220. }
  221. if(SI2176_DEBUG)
  222. pr_info("%s: atv_video_mode.video_sys:%d ..........\n", __func__, si_prop.atv_video_mode.video_sys);
  223. }
  224. void tvin_demod_get_afc(struct tuner_parm_s *ptp)
  225. {
  226. #if 0
  227. if (si_common_reply.tunint && si_common_reply.atvint)
  228. {
  229. pr_info("%s: AFC valid!!!!...tunint:%d.atvint:%d.....\n", __func__,
  230. si_common_reply.tunint,
  231. si_common_reply.atvint);
  232. ptp->if_status = 0xE0;
  233. }
  234. else
  235. {
  236. ptp->if_status = 0;
  237. pr_info("%s: AFC bad.........\n", __func__);
  238. }
  239. #else
  240. si2176_atv_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply);
  241. #if 0
  242. if (!si_cmd_reply.atv_status.status->atvint || !si_cmd_reply.atv_status.status->tunint)
  243. {
  244. pr_info("%s: demod unstable atvint:%d tunint:%d............\n", __func__,
  245. si_cmd_reply.atv_status.status->atvint,
  246. si_cmd_reply.atv_status.status->tunint);
  247. ptp->if_status = 0;
  248. }
  249. #endif
  250. if (si_cmd_reply.atv_status.pcl && si_cmd_reply.atv_status.dl)
  251. {
  252. ptp->if_status = 0xE0;
  253. if(SI2176_DEBUG)
  254. pr_info("%s: AFC & demod locked:0x%x \n", __func__, ptp->if_status);
  255. }
  256. else
  257. {
  258. if(SI2176_DEBUG)
  259. pr_info("%s: AFC & demod unlocked atvint:%d tunint:%d \n", __func__,
  260. si_cmd_reply.atv_status.status->atvint,
  261. si_cmd_reply.atv_status.status->tunint);
  262. }
  263. #endif
  264. }
  265. #ifdef CONFIG_TVIN_TUNER_SI2176
  266. void si2176_get_tuner_status(struct si2176_tuner_status_s *si2176_s)
  267. {
  268. if(si2176_tuner_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply)!=0)
  269. {
  270. pr_info("%s:get si2176 tuner status error!!!\n",__func__);
  271. return;
  272. }
  273. si2176_s->si2176_tuner_s.tcint = si_cmd_reply.tuner_status.tcint;
  274. si2176_s->si2176_tuner_s.rssilint = si_cmd_reply.tuner_status.rssilint;
  275. si2176_s->si2176_tuner_s.rssihint = si_cmd_reply.tuner_status.rssihint;
  276. si2176_s->si2176_tuner_s.vco_code = si_cmd_reply.tuner_status.vco_code;
  277. si2176_s->si2176_tuner_s.tc = si_cmd_reply.tuner_status.tc;
  278. si2176_s->si2176_tuner_s.rssil = si_cmd_reply.tuner_status.rssil;
  279. si2176_s->si2176_tuner_s.rssih = si_cmd_reply.tuner_status.rssih;
  280. si2176_s->si2176_tuner_s.rssi = si_cmd_reply.tuner_status.rssi;
  281. si2176_s->si2176_tuner_s.freq = si_cmd_reply.tuner_status.freq;
  282. si2176_s->si2176_tuner_s.mode = si_cmd_reply.tuner_status.mode;
  283. if(SI2176_DEBUG)
  284. {
  285. pr_info("%s:get si2176_tuner_status:tcint %u,rssilint %u,rssihint \
  286. %u,vco_code %d,tc %u,rssil %u,rssih %u,rssi %d,freq %u,mode %u.\n",\
  287. __func__,si2176_s->si2176_tuner_s.tcint,si2176_s->si2176_tuner_s.rssilint,\
  288. si2176_s->si2176_tuner_s.rssihint,si2176_s->si2176_tuner_s.vco_code,\
  289. si2176_s->si2176_tuner_s.tc,si2176_s->si2176_tuner_s.rssil,si2176_s->si2176_tuner_s.rssih,\
  290. si2176_s->si2176_tuner_s.rssi,si2176_s->si2176_tuner_s.freq,si2176_s->si2176_tuner_s.mode);
  291. }
  292. if(si2176_atv_status(tuner_client, SI2176_ATV_STATUS_CMD_INTACK_OK, &si_cmd_reply)!=0)
  293. {
  294. pr_info("%s:get si2176 atv status error!!!\n",__func__);
  295. return;
  296. }
  297. si2176_s->si2176_atv_s.chlint = si_cmd_reply.atv_status.chlint;
  298. si2176_s->si2176_atv_s.pclint = si_cmd_reply.atv_status.pclint;
  299. si2176_s->si2176_atv_s.dlint = si_cmd_reply.atv_status.dlint;
  300. si2176_s->si2176_atv_s.snrlint = si_cmd_reply.atv_status.snrlint;
  301. si2176_s->si2176_atv_s.snrhint = si_cmd_reply.atv_status.snrhint;
  302. si2176_s->si2176_atv_s.audio_chan_bw = si_cmd_reply.atv_status.audio_chan_bw;
  303. si2176_s->si2176_atv_s.chl = si_cmd_reply.atv_status.chl;
  304. si2176_s->si2176_atv_s.pcl = si_cmd_reply.atv_status.pcl;
  305. si2176_s->si2176_atv_s.dl = si_cmd_reply.atv_status.dl;
  306. si2176_s->si2176_atv_s.snrl = si_cmd_reply.atv_status.snrl;
  307. si2176_s->si2176_atv_s.snrh = si_cmd_reply.atv_status.snrh;
  308. si2176_s->si2176_atv_s.video_snr = si_cmd_reply.atv_status.video_snr;
  309. si2176_s->si2176_atv_s.afc_freq = si_cmd_reply.atv_status.afc_freq;
  310. si2176_s->si2176_atv_s.video_sc_spacing = si_cmd_reply.atv_status.video_sc_spacing;
  311. si2176_s->si2176_atv_s.video_sys = si_cmd_reply.atv_status.video_sys;
  312. si2176_s->si2176_atv_s.color = si_cmd_reply.atv_status.color;
  313. si2176_s->si2176_atv_s.trans = si_cmd_reply.atv_status.trans;
  314. si2176_s->si2176_atv_s.audio_sys = si_cmd_reply.atv_status.audio_sys;
  315. si2176_s->si2176_atv_s.audio_demod_mode = si_cmd_reply.atv_status.audio_demod_mode;
  316. if(SI2176_DEBUG)
  317. {
  318. pr_info("%s:get_si2176_atv_status:chlint %u,pclint %u,dlint %u,snrlint \
  319. %u,snrhint %u,audio_chan_bw %u,chl %u,pcl %u,dl %u,snrl %u,snrh \
  320. %u,video_snr %u,afe_freq %d,video_sc_spacing %d,video_sys %u,color \
  321. %u,audio_sys %u,audio_demod_mode %u.\n",__func__,si2176_s->si2176_atv_s.chlint,si2176_s->si2176_atv_s.pclint,\
  322. si2176_s->si2176_atv_s.dlint,si2176_s->si2176_atv_s.snrlint,si2176_s->si2176_atv_s.snrhint,\
  323. si2176_s->si2176_atv_s.audio_chan_bw,si2176_s->si2176_atv_s.chl,si2176_s->si2176_atv_s.pcl,\
  324. si2176_s->si2176_atv_s.dl,si2176_s->si2176_atv_s.snrl,si2176_s->si2176_atv_s.snrh,\
  325. si2176_s->si2176_atv_s.video_snr,si2176_s->si2176_atv_s.afc_freq,si2176_s->si2176_atv_s.video_sc_spacing,\
  326. si2176_s->si2176_atv_s.video_sys,si2176_s->si2176_atv_s.color,si2176_s->si2176_atv_s.audio_sys,\
  327. si2176_s->si2176_atv_s.audio_demod_mode);
  328. }
  329. }
  330. #endif
  331. static int si2176_tuner_probe(struct i2c_client *client, const struct i2c_device_id *id)
  332. {
  333. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  334. pr_info("%s: functionality check failed\n", __FUNCTION__);
  335. return -ENODEV;
  336. }
  337. tuner_client = client;
  338. if(SI2176_DEBUG)
  339. pr_info( "tuner_client->addr = 0x%x\n", tuner_client->addr);
  340. //int si2176
  341. si2176_init(tuner_client, &si_cmd_reply, &si_common_reply);
  342. si2176_configure(tuner_client, &si_prop, &si_cmd_reply, &si_common_reply);
  343. return 0;
  344. }
  345. static int si2176_tuner_remove(struct i2c_client *client)
  346. {
  347. if(SI2176_DEBUG)
  348. pr_info("%s driver removed ok.\n", client->name);
  349. return 0;
  350. }
  351. static const struct i2c_device_id si2176_tuner_id[] = {
  352. {SI2176_TUNER_I2C_NAME, 0},
  353. { }
  354. };
  355. MODULE_DEVICE_TABLE(i2c, si2176_tuner_id);
  356. static struct i2c_driver si2176_tuner_driver = {
  357. .driver = {
  358. .owner = THIS_MODULE,
  359. .name = SI2176_TUNER_I2C_NAME,
  360. },
  361. .probe = si2176_tuner_probe,
  362. .remove = si2176_tuner_remove,
  363. .id_table = si2176_tuner_id,
  364. };
  365. static int __init si2176_tuner_init(void)
  366. {
  367. int ret = 0;
  368. ret = i2c_add_driver(&si2176_tuner_driver);
  369. if (ret < 0 || tuner_client == NULL) {
  370. pr_err("tuner: failed to add i2c driver. \n");
  371. ret = -ENOTSUPP;
  372. }
  373. return ret;
  374. }
  375. static void __exit si2176_tuner_exit(void)
  376. {
  377. if(SI2176_DEBUG)
  378. pr_info( "%s . \n", __FUNCTION__ );
  379. i2c_del_driver(&si2176_tuner_driver);
  380. }
  381. MODULE_AUTHOR("Bobby Yang <bo.yang@amlogic.com>");
  382. MODULE_DESCRIPTION("Xuguang htm-9a-w125 tuner i2c device driver");
  383. MODULE_LICENSE("GPL");
  384. module_init(si2176_tuner_init);
  385. module_exit(si2176_tuner_exit);